summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndistapi
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/ndistapi
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/ndistapi/intrface.h138
-rw-r--r--private/ntos/ndis/ndistapi/makefile7
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.c2873
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.rc38
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.src7
-rw-r--r--private/ntos/ndis/ndistapi/private.h251
-rw-r--r--private/ntos/ndis/ndistapi/sources40
7 files changed, 3354 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndistapi/intrface.h b/private/ntos/ndis/ndistapi/intrface.h
new file mode 100644
index 000000000..6babe2fb5
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/intrface.h
@@ -0,0 +1,138 @@
+/*++ BUILD Version: 0000 // Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ intrface.h
+
+Abstract:
+
+ Definition for user-mode/kernel-mode tapi/connection wrapper interface.
+
+Author:
+
+ Dan Knudson (DanKn) 20-Feb-1994
+
+Revision History:
+
+--*/
+
+
+
+#define NDISTAPIERR_UNINITIALIZED 0x00001001
+#define NDISTAPIERR_BADDEVICEID 0x00001002
+#define NDISTAPIERR_DEVICEOFFLINE 0x00001003
+
+
+
+//
+// Define the various device type values. Note that values used by Microsoft
+// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+// by customers.
+//
+
+#define FILE_DEVICE_NDISTAPI 0x00008fff
+
+
+
+//
+// Macro definition for defining IOCTL and FSCTL function control codes. Note
+// that function codes 0-2047 are reserved for Microsoft Corporation, and
+// 2048-4095 are reserved for customers.
+//
+
+#define NDISTAPI_IOCTL_INDEX 0x8f0
+
+
+
+//
+// The NDISTAPI device driver IOCTLs
+//
+
+#define IOCTL_NDISTAPI_CONNECT CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_DISCONNECT CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_QUERY_INFO CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_SET_INFO CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_GET_LINE_EVENTS CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+
+//
+// Type definitions
+//
+
+typedef struct _NDISTAPI_REQUEST
+{
+ //
+ // Return value
+ //
+
+ OUT ULONG ulReturnValue;
+
+ //
+ // Operation idenfifier
+ //
+
+ IN ULONG Oid;
+
+ //
+ // Target line device ID
+ //
+
+ IN ULONG ulDeviceID;
+
+ //
+ // Total size of request data in buffer
+ //
+
+ IN ULONG ulDataSize;
+
+ //
+ // Buffer for request data
+ //
+
+ IN OUT UCHAR Data[1];
+
+} NDISTAPI_REQUEST, *PNDISTAPI_REQUEST;
+
+
+typedef struct _NDISTAPI_EVENT_DATA
+{
+ //
+ // Total size of the event data buffer
+ //
+
+ IN ULONG ulTotalSize;
+
+ //
+ // Size of the returned event data
+ //
+
+ OUT ULONG ulUsedSize;
+
+ //
+ // Event data buffer
+ //
+
+ OUT UCHAR Data[1];
+
+} NDISTAPI_EVENT_DATA, *PNDISTAPI_EVENT_DATA;
diff --git a/private/ntos/ndis/ndistapi/makefile b/private/ntos/ndis/ndistapi/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndistapi/ndistapi.c b/private/ntos/ndis/ndistapi/ndistapi.c
new file mode 100644
index 000000000..ea37cd6b3
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.c
@@ -0,0 +1,2873 @@
+/*++ 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 "ntos.h"
+#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 ULONG DbgLevel,
+ IN PUCHAR DbgMessage,
+ IN ...
+ );
+#endif
+
+VOID
+DoProviderInitComplete(
+ PPROVIDER_REQUEST ProviderRequest
+ );
+
+ULONG
+GetLineEvents(
+ PVOID EventBuffer,
+ ULONG BufferSize
+ );
+
+VOID
+GetRegistryParameters(
+ IN PUNICODE_STRING RegistryPath
+);
+
+BOOLEAN
+SyncInitAllProviders(
+ void
+ );
+
+NDIS_STATUS
+SendProviderInitRequest(
+ PPROVIDER_INFO Provider
+ );
+
+NDIS_STATUS
+SendProviderShutdown(
+ PPROVIDER_INFO Provider
+ );
+
+
+//
+// Use the alloc_text pragma to specify the driver initialization routines
+// (they can be paged out).
+//
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#pragma alloc_text(INIT,GetRegistryParameters)
+#endif
+
+
+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 (DEVICE_EXTENSION),
+ &deviceNameUnicodeString,
+ FILE_DEVICE_NDISTAPI,
+ 0,
+ FALSE,
+ &deviceObject
+ );
+
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Init the global & sero the extension
+ //
+
+ DeviceExtension =
+ (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
+
+ RtlZeroMemory(
+ DeviceExtension,
+ sizeof (DEVICE_EXTENSION)
+ );
+
+
+ //
+ // Create a NULL-terminated registry path & retrieve the registry
+ // params (EventDataQueueLength)
+ //
+
+ registryPath.Buffer = ExAllocatePoolWithTag(
+ PagedPool,
+ RegistryPath->Length + sizeof(UNICODE_NULL),
+ 'TAPI'
+ );
+
+ 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
+ );
+ }
+
+ GetRegistryParameters (&registryPath);
+
+ ExFreePool (registryPath.Buffer);
+
+
+ //
+ // Init event data buf, state vars, spin lock, device queue, & event
+ //
+
+ DeviceExtension->EventData =
+ DeviceExtension->DataIn =
+ DeviceExtension->DataOut = ExAllocatePoolWithTag(
+ NonPagedPool,
+ DeviceExtension->EventDataQueueLength,
+ 'TAPI'
+ );
+
+ if (!DeviceExtension->DataOut)
+ {
+ DBGOUT((1, "DriverEntry: ExAllocPool for event data buf failed"));
+
+ ntStatus = STATUS_UNSUCCESSFUL;
+
+ goto DriverEntry_err;
+ }
+
+ DeviceExtension->DeviceObject = deviceObject;
+ DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
+ DeviceExtension->NdisTapiNumDevices = 0;
+ DeviceExtension->htCall = 0x80000000;
+
+ KeInitializeSpinLock (&DeviceExtension->SpinLock);
+ KeInitializeSpinLock (&DeviceExtension->EventSpinLock);
+
+ KeInitializeDeviceQueue (&DeviceExtension->DeviceQueue);
+
+ KeInitializeEvent(
+ &DeviceExtension->SyncEvent,
+ SynchronizationEvent,
+ FALSE
+ );
+
+
+ //
+ // 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)
+ {
+ if (DeviceExtension->EventData)
+ {
+ ExFreePool (DeviceExtension->EventData);
+ }
+
+ IoDeleteDevice (deviceObject);
+ }
+ }
+
+
+ DBGOUT ((2, "DriverEntry: exit"));
+
+ return ntStatus;
+}
+
+
+
+VOID
+NdisTapiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+{
+ KIRQL oldIrql;
+// KIRQL cancelIrql;
+
+
+ DBGOUT((2,"NdisTapiCancel: enter"));
+
+
+ //
+ // Release the cancel spinlock
+ //
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ //
+ // Acquire the EventSpinLock & check to see if we're canceling a
+ // pending get-events Irp
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+ if (Irp == DeviceExtension->EventsRequestIrp)
+ {
+ DeviceExtension->EventsRequestIrp = NULL;
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+ goto NdisTapiCancel_done;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // Acquire the SpinLock & try to remove request from our special
+ // user-mode requests dev queue
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (TRUE != KeRemoveEntryDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry
+ ))
+ {
+ //
+ // If we couldn't find the Irp in the device queue then it's
+ // "unknown", i.e. perhaps it was completed before we got here,
+ // so set it to NULL
+ //
+
+ Irp = NULL;
+
+ DBGOUT((1,"NdisTapiCancel: Irp 0x%x not in device queue?!?\n", Irp));
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+NdisTapiCancel_done:
+
+ if (Irp)
+ {
+ //
+ // 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=x%x", Irp));
+ }
+ else
+ {
+ DBGOUT((2,"NdisTapiCancel: irp=x%x not found, not completing!", Irp));
+ }
+
+ DBGOUT((2,"NdisTapiCancel: exit"));
+
+ return;
+}
+
+
+
+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.
+
+--*/
+
+{
+ PIRP irp;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ BOOLEAN completeRequest;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PKDEVICE_QUEUE_ENTRY packet;
+
+
+ DBGOUT((2,"NdisTapiCleanup: enter"));
+
+
+ //
+ // If this cleanup originated from the NCPA then don't bother
+ // completing stuff (we don't want to possibly hose tapisrv & by
+ // canceling it's requests)
+ //
+
+ if (DeviceExtension->NCPAFileObject &&
+ (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject))
+ {
+ goto NdisTapiCleanup_CompleteRequest;
+ }
+
+
+ //
+ // Sync access to EventsRequestIrp by acquiring EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+
+ //
+ // Check to see if there's a get-events request pending that needs
+ // completing
+ //
+
+ completeRequest = FALSE;
+
+ if (DeviceExtension->EventsRequestIrp)
+ {
+ //
+ // Acquire the cancel spinlock, remove the request from the
+ // cancellable state, and free the cancel spinlock.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ irp = DeviceExtension->EventsRequestIrp;
+ IoSetCancelRoutine (irp, NULL);
+ DeviceExtension->EventsRequestIrp = NULL;
+ IoReleaseCancelSpinLock (cancelIrql);
+
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ irp->IoStatus.Information = 0;
+
+ completeRequest = TRUE;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+ if (completeRequest)
+ {
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2,"NdisTapiCleanup: completing GET_EVENTS request x%x", irp));
+ }
+
+
+ //
+ // Sync access to our request device queue by acquiring SpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+
+ //
+ // Cancel all outstanding QUERY/SET_INFO requests
+ //
+
+ if (DeviceExtension->DeviceQueue.Busy == TRUE)
+ {
+ IoAcquireCancelSpinLock (&cancelIrql);
+
+ while ((packet = KeRemoveDeviceQueue (&DeviceExtension->DeviceQueue))
+ != NULL)
+ {
+ irp = CONTAINING_RECORD(
+ packet,
+ IRP,
+ Tail.Overlay.DeviceQueueEntry
+ );
+
+ //
+ // Remove the IRP from the cancelable state
+ //
+
+ IoSetCancelRoutine (irp, NULL);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock since IoCompleteRequest() must be
+ // called at <= DISPATCH_LEVEL
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // Set the status & info size values appropriately, & complete
+ // the request
+ //
+
+ ndisTapiRequest = irp->AssociatedIrp.SystemBuffer;
+ ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_FAILURE;
+
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ irp->IoStatus.Information = 0;
+
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2,"NdisTapiCleanup: completing QRY/SET request x%x", irp));
+
+
+ //
+ // Reacquire the SpinLock protecting the device queue
+ // & the cancel spinlock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+ IoAcquireCancelSpinLock (&cancelIrql);
+ }
+
+ IoReleaseCancelSpinLock (cancelIrql);
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+
+ //
+ // Complete the cleanup request with STATUS_SUCCESS.
+ //
+
+NdisTapiCleanup_CompleteRequest:
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+
+ DBGOUT((2,"NdisTapiCleanup: exit\n"));
+
+ 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:
+
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PVOID ioBuffer;
+ ULONG inputBufferLength;
+ ULONG outputBufferLength;
+ ULONG ioControlCode;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION irpStack;
+
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+
+ //
+ // 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=x%x", Irp));
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ DBGOUT ((2, "IRP_MJ_CLOSE, Irp=x%x", Irp));
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (DeviceExtension->NCPAFileObject &&
+ DeviceExtension->TapiSrvFileObject)
+ {
+ //
+ // Both TapiSrv & NCPA are currently running, so we
+ // don't want to shutdown the providers/chg state because
+ // one is closing
+ //
+ }
+ else if ((Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject) ||
+
+ (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->TapiSrvFileObject))
+ {
+ //
+ // Either the NCPA or TapiSrv (but no both) was running,
+ // but is now shutting down, so send shutdown msg to providers
+ // & chg state
+ //
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED)
+ {
+ PPROVIDER_INFO provider;
+
+
+ //
+ // State change
+ //
+
+ DeviceExtension->Status =
+ NDISTAPI_STATUS_DISCONNECTING;
+
+
+ //
+ // Send the providers a shutdown request
+ //
+
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ switch (provider->Status)
+ {
+ case PROVIDER_STATUS_ONLINE:
+ case PROVIDER_STATUS_PENDING_INIT:
+
+ //
+ // Reset provider status
+ //
+
+ provider->Status = PROVIDER_STATUS_PENDING_INIT;
+
+ SendProviderShutdown (provider);
+
+ break;
+
+ case PROVIDER_STATUS_OFFLINE:
+
+ //
+ // If provider is currently offline just remove it
+ // since it's not wanting to talk to us right now
+ //
+
+ // PnP provider = DoRemoveProvider (provider);
+
+ break;
+
+ }
+
+ provider = provider->Next;
+ }
+
+
+ //
+ // State change
+ //
+
+ DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
+ }
+ }
+
+
+ //
+ // Zero the DeviceExtension->XxxFileObject as appropriate
+ // (Note that we actually get two close requests from each
+ // client, since the each open both a sync & an async driver
+ // handle)
+ //
+
+ if (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject)
+ {
+ DeviceExtension->NCPAFileObject = NULL;
+ }
+ else if (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->TapiSrvFileObject)
+ {
+ DeviceExtension->TapiSrvFileObject = NULL;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
+
+ switch (ioControlCode)
+ {
+ case IOCTL_NDISTAPI_CONNECT:
+ {
+ DBGOUT ((2, "IOCTL_NDISTAPI_CONNECT, Irp=x%x", Irp));
+
+
+ //
+ // Someone's connecting. Make sure they passed us a valid
+ // info buffer
+ //
+
+ if ((inputBufferLength < 2*sizeof(ULONG)) ||
+ (outputBufferLength < sizeof(ULONG))
+ )
+ {
+ DBGOUT ((3, "IOCTL_NDISTAPI_CONNECT: buffer too small"));
+
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+
+ break;
+ }
+
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_DISCONNECTED)
+ {
+ DeviceExtension->Status = NDISTAPI_STATUS_CONNECTING;
+
+
+ //
+ // Reset the async event buf count & pointers
+ //
+
+ DeviceExtension->EventCount = 0;
+ DeviceExtension->DataIn =
+ DeviceExtension->DataOut = DeviceExtension->EventData;
+
+
+ //
+ // Synchronously init all providers
+ //
+
+ SyncInitAllProviders();
+ }
+
+
+ //
+ // Check to see if this is the NCPA
+ //
+
+ if (*(((ULONG *) ioBuffer) + 1) == 0)
+ {
+ DeviceExtension->NCPAFileObject =
+ Irp->Tail.Overlay.OriginalFileObject;
+ }
+ else
+ {
+ DeviceExtension->TapiSrvFileObject =
+ Irp->Tail.Overlay.OriginalFileObject;
+ }
+
+
+ //
+ // Return the number of line devs
+ //
+
+ *((ULONG *) ioBuffer)=
+ DeviceExtension->NdisTapiNumDevices;
+
+ DeviceExtension->Status = NDISTAPI_STATUS_CONNECTED;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(ULONG);
+
+ break;
+ }
+
+ case IOCTL_NDISTAPI_QUERY_INFO:
+ case IOCTL_NDISTAPI_SET_INFO:
+ {
+ ULONG targetDeviceID;
+ NDIS_STATUS ndisStatus;
+ NDIS_HANDLE providerHandle = NULL;
+ REQUEST_PROC requestProc;
+ PPROVIDER_INFO provider;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PPROVIDER_REQUEST providerRequest;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+
+
+ DBGOUT ((2, "IOCTL_NDISTAPI_QUERY/SET_INFO, Irp=x%x", Irp));
+
+
+ //
+ // Verify we're connected, then check the device ID of the
+ // incoming request against our list of online devices
+ //
+
+ ndisTapiRequest = ioBuffer;
+
+ targetDeviceID = ndisTapiRequest->ulDeviceID;
+
+ DBGOUT((
+ 3,
+ "\tOid=0x%x, retVal=0x%x, devID=%d, dataSize=%d, reqID=%d, parm1=0x%x",
+ ndisTapiRequest->Oid,
+ ndisTapiRequest->ulReturnValue,
+ ndisTapiRequest->ulDeviceID,
+ ndisTapiRequest->ulDataSize,
+ *((ULONG *)ndisTapiRequest->Data),
+ *(((ULONG *)ndisTapiRequest->Data) + 1)
+ ));
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED)
+ {
+ DBGOUT((3, "\tunconnected, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_UNINITIALIZED;
+ }
+
+ else if ((targetDeviceID <
+ DeviceExtension->NdisTapiDeviceIDBase) ||
+ (targetDeviceID >=
+ DeviceExtension->NdisTapiDeviceIDBase +
+ DeviceExtension->NdisTapiNumDevices))
+ {
+ DBGOUT((3, "\tdev ID out of range, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_BADDEVICEID;
+ }
+
+ else
+ {
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ if ((provider->Status == PROVIDER_STATUS_ONLINE) &&
+ (targetDeviceID >= provider->DeviceIDBase) &&
+ (targetDeviceID <
+ provider->DeviceIDBase + provider->NumDevices)
+ )
+ {
+ providerHandle = provider->ProviderHandle;
+ requestProc = provider->RequestProc;
+
+ break;
+ }
+
+ provider = provider->Next;
+ }
+
+ if (provider == NULL)
+ {
+ DBGOUT((3, "dev offline, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_DEVICEOFFLINE;
+ }
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ if (providerHandle == NULL)
+ {
+ //
+ // Set Irp->IoStatus.Information large enough that err code
+ // gets copied back to user buffer
+ //
+
+ Irp->IoStatus.Information = sizeof(ULONG);
+
+ break;
+ }
+
+
+ //
+ // Create the providerRequest & submit it
+ //
+
+ providerRequest = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_REQUEST) + ndisTapiRequest->ulDataSize -
+ sizeof(ULONG), // to acct for ULONG in PROVIDER_REQUEST
+ 'TAPI'
+ );
+
+ if (!providerRequest)
+ {
+ DBGOUT((1, "NdisTapiDispatch: unable to alloc request buf"));
+
+ Irp->IoStatus.Information = sizeof (ULONG);
+
+ ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_RESOURCES;
+
+ break;
+ }
+
+ providerRequest->NdisRequest.RequestType =
+ (ioControlCode == IOCTL_NDISTAPI_QUERY_INFO ?
+ NdisRequestQueryInformation : NdisRequestSetInformation);
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ ndisTapiRequest->Oid;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ ndisTapiRequest->ulDataSize;
+
+ providerRequest->Provider = provider;
+
+ RtlMoveMemory(
+ providerRequest->Data,
+ ndisTapiRequest->Data,
+ ndisTapiRequest->ulDataSize
+ );
+
+
+ //
+ // Queue up this TAPI request in our special device queue
+ // prior to submitting the provider request.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
+
+ if (!KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ ))
+ {
+ //
+ // If here the queue was not busy, but KeInsertXxx marked
+ // it busy, so try again. We want to toss this in the
+ // queue regardless- it's just going to sit there until
+ // the corresponding provider request is completed, or the
+ // TAPI request is canceled.
+ //
+
+ KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ );
+ }
+
+ KeLowerIrql (oldIrql);
+
+
+ //
+ // Mark the TAPI request pending
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+
+ //
+ // Set the cancel routine for the TAPI request
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ IoSetCancelRoutine (Irp, NdisTapiCancel);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Call the provider's request proc
+ //
+
+ ndisStatus = (*requestProc)(
+ providerHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+
+ //
+ // 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)
+ {
+ return STATUS_PENDING;
+ }
+ else
+ {
+ DBGOUT((
+ 1,
+ "IOCTL_TAPI_SET/QUERY_INFO: reqProc return !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 since the NdisTapiCompleteRequest
+ // func might have removed this request temporarily.
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ KeRemoveByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ );
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // Mark request as successfully completed
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+
+ //
+ // 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 ((ioControlCode == IOCTL_NDISTAPI_QUERY_INFO) &&
+ (ndisStatus == NDIS_STATUS_SUCCESS))
+ {
+ RtlMoveMemory(
+ ndisTapiRequest->Data,
+ providerRequest->Data,
+ ndisTapiRequest->ulDataSize
+ );
+
+ Irp->IoStatus.Information =
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ else
+ {
+ Irp->IoStatus.Information = sizeof (ULONG);
+ }
+
+ ndisTapiRequest->ulReturnValue = ndisStatus;
+
+
+ //
+ // Free the providerRequest
+ //
+
+ ExFreePool (providerRequest);
+ }
+
+ break;
+ }
+
+ case IOCTL_NDISTAPI_GET_LINE_EVENTS:
+ {
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ BOOLEAN satisfiedRequest = FALSE;
+
+
+ DBGOUT ((2, "IOCTL_NDISTAPI_GET_LINE_EVENTS, Irp=x%x", Irp));
+
+
+ //
+ // Sync event buf access by acquiring EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+
+ //
+ // Inspect DeviceExtension to see if there's any data available
+ //
+
+ if (DeviceExtension->EventCount != 0)
+ {
+ //
+ // There's line event data queued in our ring buffer. Grab as
+ // much as we can & complete the request.
+ //
+
+ PNDISTAPI_EVENT_DATA ndisTapiEventData = ioBuffer;
+
+
+ ndisTapiEventData->ulUsedSize = GetLineEvents(
+ ndisTapiEventData->Data,
+ ndisTapiEventData->ulTotalSize
+ );
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = ndisTapiEventData->ulUsedSize +
+ sizeof(NDISTAPI_EVENT_DATA) - 1;
+
+ satisfiedRequest = TRUE;
+ }
+ else
+ {
+ //
+ // 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.
+ //
+
+ DeviceExtension->EventsRequestIrp = Irp;
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ IoSetCancelRoutine (Irp, NdisTapiCancel);
+ IoReleaseCancelSpinLock (cancelIrql);
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // If request not satisfied just return pending
+ //
+
+ if (!satisfiedRequest)
+ {
+ return STATUS_PENDING;
+ }
+
+ break;
+ }
+
+ default:
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ DBGOUT ((2, "unknown IRP_MJ_DEVICE_CONTROL"));
+
+ break;
+
+ } // switch
+
+ break;
+ }
+
+
+ //
+ // DON'T try to use the status field of the irp in the return
+ // status. That IRP IS GONE as soon as you call IoCompleteRequest.
+ //
+
+ if ((ntStatus = Irp->IoStatus.Status) != STATUS_PENDING)
+ {
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ DBGOUT((3, "NdisTapiDispatch: completed Irp=x%x", Irp));
+ }
+ else
+ {
+ DBGOUT((3, "NdisTapiDispatch: pending Irp=x%x", 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:
+
+
+--*/
+
+{
+ PPROVIDER_INFO provider, nextProvider;
+
+
+ DBGOUT ((2, "NdisTapiUnload: enter"));
+
+
+ //
+ // Delete the device object & sundry resources
+ //
+
+ ExFreePool (DeviceExtension->EventData);
+
+ provider = DeviceExtension->Providers, nextProvider;
+
+ while (provider != NULL)
+ {
+ nextProvider = provider->Next;
+
+ ExFreePool (provider);
+
+ provider = nextProvider;
+ }
+
+ IoDeleteDevice (DriverObject->DeviceObject);
+
+ DBGOUT ((2, "NdisTapiUnload: exit"));
+
+ return;
+}
+
+
+
+VOID
+NdisTapiRegisterProvider(
+ IN NDIS_HANDLE ProviderHandle,
+ IN REQUEST_PROC RequestProc
+ )
+
+/*++
+
+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"));
+
+
+ //
+ // Create a new provider instance
+ //
+
+ newProvider = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_INFO),
+ 'TAPI'
+ );
+
+ newProvider->Status = PROVIDER_STATUS_PENDING_INIT;
+ newProvider->ProviderHandle = ProviderHandle;
+ newProvider->RequestProc = RequestProc;
+ newProvider->Next = NULL;
+
+
+
+ //
+ // Grab the spin lock & add the new provider, and see whether to
+ // send the provider an init request
+ //
+
+// KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if ((provider = DeviceExtension->Providers) == NULL)
+ {
+ DeviceExtension->Providers = newProvider;
+ }
+ else
+ {
+ while (provider->Next != NULL)
+ {
+ provider = provider->Next;
+ }
+
+ provider->Next = 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) &&
+ (DeviceExtension->ProviderInitPending == FALSE)
+ )
+ {
+ ndisStatus = SendProviderInitRequest (newProvider);
+
+ if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ DeviceExtension->ProviderInitPending == TRUE;
+ }
+ }
+
+// KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ // Pnp: we should keep track of the current # of providers
+ // registered, so that we can bump up NdisTapiNumDevices
+ // appropriately
+
+ return;
+}
+
+
+
+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
+ //
+
+ provider = DeviceExtension->Providers;
+
+ if (provider == NULL)
+ {
+ goto NdisTapiDeregisterProvider_err;
+ }
+
+ while (provider->ProviderHandle != ProviderHandle)
+ {
+ previousProvider = provider;
+
+ provider = provider->Next;
+
+ if (provider == NULL)
+ {
+ goto NdisTapiDeregisterProvider_err;
+ }
+ }
+
+
+ //
+ // Do the right thing according to the current NdisTapi state
+ //
+
+ switch (DeviceExtension->Status)
+ {
+ case NDISTAPI_STATUS_CONNECTED:
+
+ //
+ // Mark provider as offline
+ //
+
+ provider->Status = PROVIDER_STATUS_OFFLINE;
+
+
+ // 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 (provider == DeviceExtension->Providers)
+ {
+ DeviceExtension->Providers = provider->Next;
+ }
+ else
+ {
+ previousProvider->Next = provider->Next;
+ }
+
+ ExFreePool (provider);
+
+ break;
+
+ case NDISTAPI_STATUS_CONNECTING:
+
+ // PnP: implement
+
+ break;
+
+ } // switch
+
+ goto NdisTapiDeregisterProvider_ReleaseSpinLock;
+
+
+NdisTapiDeregisterProvider_err:
+
+ DBGOUT((0, "NdisTapiDeregisterProvider: bad provider handle"));
+
+
+NdisTapiDeregisterProvider_ReleaseSpinLock:
+
+// KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ DBGOUT((2, "NdisTapiDeregisterProvider: exit"));
+
+ return;
+}
+
+
+
+VOID
+NdisTapiIndicateStatus(
+ IN ULONG 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;
+ KIRQL cancelIrql;
+ 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 EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &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. Note that valid htCall values as generated by
+ // this driver range between 0x80000000 and 0xfffffffe (the
+ // user-mode tapi server reserves the range 0x1-0x7fffffff).
+ //
+
+ ndisTapiEvent = StatusBuffer;
+
+ if (ndisTapiEvent->ulMsg == LINE_NEWCALL)
+ {
+ ndisTapiEvent->ulParam2 = DeviceExtension->htCall;
+
+ DeviceExtension->htCall++;
+
+ if (DeviceExtension->htCall > 0xfffffffe)
+ {
+ DeviceExtension->htCall = 0x80000000;
+ }
+ }
+
+
+ //
+ // Check of there is an outstanding request to satisfy
+ //
+
+ if (DeviceExtension->EventsRequestIrp)
+ {
+ //
+ // Acquire the cancel spinlock, remove the request from the
+ // cancellable state, and free the cancel spinlock.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ irp = DeviceExtension->EventsRequestIrp;
+ IoSetCancelRoutine (irp, NULL);
+ DeviceExtension->EventsRequestIrp = NULL;
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // 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;
+ }
+
+
+ //
+ // If there is still data in the input data queue, move it
+ // to the event data queue
+ //
+
+ StatusBuffer = ((PCHAR) StatusBuffer) + moveSize;
+
+ moveSize = bytesInQueue - moveSize;
+
+ if (moveSize > 0)
+ {
+ //
+ // Move the remaining data from the status data queue to the
+ // event data queue. The move will happen in two parts in
+ // the case where the event data buffer wraps.
+ //
+
+ bytesInQueue =
+ DeviceExtension->EventDataQueueLength -
+ (DeviceExtension->EventCount * sizeof(NDIS_TAPI_EVENT));
+
+ bytesToMove = moveSize;
+
+ if (bytesInQueue == 0)
+ {
+ //
+ // Refuse to move any bytes that would cause an event data
+ // queue overflow. Just drop the bytes on the floor, and
+ // log an overrun error.
+ //
+
+ DBGOUT((1,"NdisTapiIndicateStatus: event queue overflow"));
+ }
+ else
+ {
+ //
+ // There is room in the event data queue, so move the
+ // remaining status data to it.
+ //
+ // bytesToMove <- MIN(Number of unused bytes in event data queue,
+ // Number of bytes remaining in status buffer)
+ //
+ // This is the total number of bytes that actually will move from
+ // the status data buffer to the event data queue.
+ //
+
+ bytesToMove = (bytesInQueue < bytesToMove) ?
+ bytesInQueue : bytesToMove;
+
+
+ //
+ // bytesInQueue <- Number of unused bytes from insertion pointer
+ // to the end of the event data queue (i.e., until the buffer
+ // wraps)
+ //
+
+ bytesInQueue =
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength) -
+ (PCHAR) DeviceExtension->DataIn;
+
+
+ //
+ // moveSize <- Number of bytes to handle in the first move.
+ //
+
+ moveSize = (bytesToMove < bytesInQueue) ?
+ bytesToMove : bytesInQueue;
+
+
+ //
+ // Do the move from the status data buffer to the event data queue
+ //
+
+ RtlMoveMemory(
+ (PCHAR) DeviceExtension->DataIn,
+ (PCHAR) StatusBuffer,
+ moveSize
+ );
+
+ //
+ // Increment the event data queue pointer and the status data
+ // buffer insertion pointer. Wrap the insertion pointer,
+ // if necessary.
+ //
+
+ StatusBuffer = ((PCHAR) StatusBuffer) + moveSize;
+
+ DeviceExtension->DataIn =
+ ((PCHAR) DeviceExtension->DataIn) + moveSize;
+
+ if ((PCHAR) DeviceExtension->DataIn >=
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength))
+ {
+ DeviceExtension->DataIn = DeviceExtension->EventData;
+ }
+
+ if ((bytesToMove - moveSize) > 0)
+ {
+ //
+ // Special case. The data must wrap in the event data
+ // buffer. Copy the rest of the status data into the
+ // beginning of the event data queue.
+ //
+
+ //
+ // moveSize <- Number of bytes to handle in the second move.
+ //
+
+ moveSize = bytesToMove - moveSize;
+
+
+ //
+ // Do the move from the status data buffer to the event data
+ // queue
+ //
+
+ RtlMoveMemory(
+ (PCHAR) DeviceExtension->DataIn,
+ (PCHAR) StatusBuffer,
+ moveSize
+ );
+
+ //
+ // Update the event data queue insertion pointer
+ //
+
+ DeviceExtension->DataIn =
+ ((PCHAR) DeviceExtension->DataIn) + moveSize;
+ }
+
+ //
+ // Update the event data queue counter
+ //
+
+ DeviceExtension->EventCount +=
+ (bytesToMove / sizeof(NDIS_TAPI_EVENT));
+ }
+ }
+
+
+ //
+ // Release the spinlock
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // If we satisfied an outstanding get events request then complete it
+ //
+
+ if (satisfiedPendingEventsRequest)
+ {
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2, "NdisTapiIndicateStatus: completion req 0x%x", 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;
+ KIRQL cancelIrql;
+ ULONG requestID;
+// PPROVIDER_INFO provider;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PPROVIDER_REQUEST providerRequest = (PPROVIDER_REQUEST) NdisRequest;
+ PIO_STACK_LOCATION irpStack;
+ PKDEVICE_QUEUE_ENTRY packet;
+
+
+ DBGOUT ((2, "NdisTapiCompleteRequest: enter"));
+
+
+ requestID = providerRequest->Data[0];
+
+
+ //
+ // Determine the type of request
+ //
+
+ if (requestID == 0)
+ {
+ //
+ // This request originated from NdisTapi.sys
+ //
+
+ switch (providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid)
+ {
+ case OID_TAPI_PROVIDER_INITIALIZE:
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ switch (DeviceExtension->Status)
+ {
+ case NDISTAPI_STATUS_CONNECTED:
+
+ // PnP: what if NdisStatus != NDIS_STATUS_SUCCESS?
+
+ DoProviderInitComplete (providerRequest);
+
+ if (SyncInitAllProviders() == TRUE)
+ {
+ DeviceExtension->ProviderInitPending = FALSE;
+ }
+
+ break;
+
+ case NDISTAPI_STATUS_DISCONNECTED:
+
+ break;
+
+ case NDISTAPI_STATUS_CONNECTING:
+
+ // PnP: what if NdisStatus != NDIS_STATUS_SUCCESS?
+
+ //
+ // Mark provider as online, etc.
+ //
+
+ DoProviderInitComplete (providerRequest);
+
+
+ //
+ // Set the event which sync's miniport inits
+ //
+
+ KeSetEvent(
+ &DeviceExtension->SyncEvent,
+ 0,
+ FALSE
+ );
+
+ break;
+
+ case NDISTAPI_STATUS_DISCONNECTING:
+
+ break;
+
+ } // switch
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ break;
+
+ case OID_TAPI_PROVIDER_SHUTDOWN:
+
+ break;
+
+ default:
+
+ DBGOUT((1, "NdisTapiCompleteRequest: unrecognized Oid"));
+
+ break;
+ }
+ }
+ else
+ {
+ //
+ // 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);
+
+
+
+ //
+ // Grab the cancel spin lock & get the IRP out of our queue.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+
+ packet = KeRemoveByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ requestID
+ );
+
+ if (packet != NULL)
+ {
+ //
+ // Get the ptrs
+ //
+
+ irp = CONTAINING_RECORD(
+ packet,
+ IRP,
+ Tail.Overlay.DeviceQueueEntry
+ );
+
+ ndisTapiRequest = irp->AssociatedIrp.SystemBuffer;
+
+
+ //
+ // Verify the IRP we got back was the one we wanted to remove
+ //
+
+ if (requestID == *((ULONG *)ndisTapiRequest->Data))
+ {
+ //
+ // Remove the IRP from the cancelable state
+ //
+
+ IoSetCancelRoutine (irp, NULL);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // 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 == 0))
+ {
+ RtlMoveMemory(
+ ndisTapiRequest->Data,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ ndisTapiRequest->ulDataSize
+ );
+
+ irp->IoStatus.Information =
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ else
+ {
+ irp->IoStatus.Information = sizeof (ULONG);
+ }
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ ndisTapiRequest->ulReturnValue = NdisStatus;
+
+
+ //
+ // Finally, complete the TAPI request
+ //
+
+ DBGOUT ((3, "completing request 0x%lx", requestID));
+
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ DBGOUT ((1, "Wrong IRP removed from queue- requeueing"));
+
+
+ //
+ // We got the wrong IRP out, the one we wanted probably
+ // has been canceled. Stick this IRP back in the queue.
+ //
+
+ if (!KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sortkey=reqID
+ ))
+ {
+ //
+ // If here the queue was not busy, but KeInsertXxx marked
+ // it busy, so try again. We want to toss this in the
+ // queue regardless- it's just going to sit there until
+ // the corresponding provider request is completed, or the
+ // TAPI request is canceled.
+ //
+
+ KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sortkey=reqID
+ );
+ }
+
+
+ //
+ // Release the cancel spin lock
+ //
+
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock.
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+ }
+ }
+ else
+ {
+ //
+ // No packets in the queue, release the cancel spin lock
+ //
+
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock.
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+ }
+ }
+
+ ExFreePool (NdisRequest);
+
+ DBGOUT ((2, "NdisTapiCompleteRequest: exit"));
+
+ return;
+}
+
+
+#if DBG
+VOID
+DbgPrt(
+ IN ULONG 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.SYS: ";
+ va_list ap;
+
+ va_start (ap, DbgMessage);
+
+ vsprintf (&buf[14], DbgMessage, ap);
+
+ strcat (buf, "\n");
+
+ DbgPrint (buf);
+
+ va_end(ap);
+ }
+
+ return;
+}
+#endif // DBG
+
+
+VOID
+DoProviderInitComplete(
+ PPROVIDER_REQUEST ProviderRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ ProviderInitRequest - pointer successfully completed init request
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller.
+
+--*/
+
+{
+ PPROVIDER_INFO provider = ProviderRequest->Provider;
+ PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData =
+ (PNDIS_TAPI_PROVIDER_INITIALIZE) ProviderRequest->Data;
+
+
+ DBGOUT ((2, "DoProviderInitComplete: enter"));
+
+
+ //
+ // Wrap this in an exception handler in case the provider was
+ // removed during an async completion
+ //
+
+ try
+ {
+ provider->Status = PROVIDER_STATUS_ONLINE;
+ provider->ProviderID = providerInitData->ulProviderID;
+ provider->NumDevices = providerInitData->ulNumLineDevs;
+
+ DBGOUT((
+ 3,
+ "providerID = 0x%lx, numDevices = 0x%lx",
+ provider->ProviderID,
+ provider->NumDevices
+ ));
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DBGOUT((1, "DoProviderInitComplete: provider invalid"));
+ }
+
+ //
+ // PnP: Check to see if this is a provider that registered &
+ // deregistered earlier (look at ProviderID's).
+ //
+
+ DBGOUT ((2, "DoProviderInitComplete: exit"));
+}
+
+
+ULONG
+GetLineEvents(
+ PCHAR EventBuffer,
+ ULONG BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->EventSpinLock held by caller.
+
+--*/
+
+{
+ ULONG bytesInQueue;
+ ULONG bytesToMove;
+ ULONG moveSize;
+
+
+ bytesInQueue = DeviceExtension->EventCount * sizeof(NDIS_TAPI_EVENT);
+
+ bytesToMove = BufferSize;
+
+ bytesToMove = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
+
+
+ //
+ // moveSize <- MIN(Number of bytes to be moved from the event data queue,
+ // Number of bytes to end of event data queue).
+ //
+
+ bytesInQueue =
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength) -
+ (PCHAR) DeviceExtension->DataOut;
+
+ moveSize = (bytesToMove < bytesInQueue) ? bytesToMove : bytesInQueue;
+
+
+ //
+ // Move bytes from the class input data queue to SystemBuffer, until
+ // the request is satisfied or we wrap the class input data buffer.
+ //
+
+ RtlMoveMemory(
+ EventBuffer,
+ (PCHAR) DeviceExtension->DataOut,
+ moveSize
+ );
+
+ EventBuffer += moveSize;
+
+
+ //
+ // If the data wraps in the event data buffer, copy the rest
+ // of the data from the start of the input data queue
+ // buffer through the end of the queued data.
+ //
+
+ if ((bytesToMove - moveSize) > 0)
+ {
+ //
+ // moveSize <- Remaining number bytes to move.
+ //
+
+ moveSize = bytesToMove - moveSize;
+
+ //
+ // Move the bytes from the
+ //
+
+ RtlMoveMemory(
+ EventBuffer,
+ (PCHAR) DeviceExtension->EventData,
+ moveSize
+ );
+
+ //
+ // Update the class input data queue removal pointer.
+ //
+
+ DeviceExtension->DataOut =
+ ((PCHAR) DeviceExtension->EventData) + moveSize;
+ }
+ else
+ {
+ //
+ // Update the input data queue removal pointer.
+ //
+
+ DeviceExtension->DataOut =
+ ((PCHAR) DeviceExtension->DataOut) + moveSize;
+ }
+
+
+ //
+ // Update the event data queue EventCount.
+ //
+
+ DeviceExtension->EventCount -=
+ (bytesToMove / sizeof(NDIS_TAPI_EVENT));
+
+ return bytesToMove;
+}
+
+
+VOID
+GetRegistryParameters(
+ IN PUNICODE_STRING RegistryPath
+)
+
+/*++
+
+Routine Description:
+
+ This routine stores the configuration information for this device.
+
+Arguments:
+
+ RegistryPath - Pointer to the null-terminated Unicode name of the
+ registry path for this driver.
+
+Return Value:
+
+ None. As a side-effect, sets DeviceExtension->EventDataQueuLength field
+
+--*/
+
+{
+ ULONG defaultDataQueueSize = 32 * sizeof(NDIS_TAPI_EVENT);
+ PWSTR path = NULL;
+ USHORT queriesPlusOne = 2;
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING parametersPath;
+ PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
+
+
+ parametersPath.Buffer = NULL;
+
+
+ //
+ // Registry path is already null-terminated, so just use it.
+ //
+
+ path = RegistryPath->Buffer;
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Allocate the Rtl query table.
+ //
+
+ parameters = ExAllocatePool(
+ PagedPool,
+ sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
+ );
+
+ if (!parameters)
+ {
+ DBGOUT((1, "NdisTapiConfiguration: ExAllocPool failed"));
+
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ RtlZeroMemory(
+ parameters,
+ sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
+ );
+
+ //
+ // Form a path to this driver's Parameters subkey.
+ //
+
+ RtlInitUnicodeString(
+ &parametersPath,
+ NULL
+ );
+
+ parametersPath.MaximumLength = RegistryPath->Length +
+ sizeof(L"\\Parameters");
+
+ parametersPath.Buffer = ExAllocatePool(
+ PagedPool,
+ parametersPath.MaximumLength
+ );
+
+ if (!parametersPath.Buffer)
+ {
+ DBGOUT((1, "NdisTapiConfiguration: ExAllocPool failed"));
+
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Form the parameters path.
+ //
+
+ RtlZeroMemory(
+ parametersPath.Buffer,
+ parametersPath.MaximumLength
+ );
+
+ RtlAppendUnicodeToString(
+ &parametersPath,
+ path
+ );
+
+ RtlAppendUnicodeToString(
+ &parametersPath,
+ L"\\Parameters"
+ );
+
+ DBGOUT((
+ 1,
+ "NdisTapiConfiguration: parameters path is %ws\n",
+ parametersPath.Buffer
+ ));
+
+
+ //
+ // Gather all of the "user specified" information from
+ // the registry.
+ //
+
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Name = L"AsyncEventQueueSize";
+ parameters[0].EntryContext =
+ &DeviceExtension->EventDataQueueLength;
+ parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultData = &defaultDataQueueSize;
+ parameters[0].DefaultLength = sizeof(ULONG);
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ parameters,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ DBGOUT((
+ 1,
+ "NdisTapiConfiguration: RtlQueryRegistryVals failed, err=x%x",
+ status
+ ));
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // Go ahead and assign driver defaults.
+ //
+
+ DeviceExtension->EventDataQueueLength = defaultDataQueueSize;
+ }
+
+
+ //
+ // Data queue ought be a least the size of the default
+ //
+
+ if (DeviceExtension->EventDataQueueLength < defaultDataQueueSize)
+ {
+ DeviceExtension->EventDataQueueLength = defaultDataQueueSize;
+ }
+
+
+ //
+ // Make sure the queue length is an integral # of (sizeof) events
+ //
+
+ DeviceExtension->EventDataQueueLength -=
+ DeviceExtension->EventDataQueueLength % sizeof(NDIS_TAPI_EVENT);
+
+
+ //
+ // Dump value
+ //
+
+ DBGOUT ((
+ 1,
+ "NdisTapiConfiguration: EventDataQueueLength = x%x",
+ DeviceExtension->EventDataQueueLength
+ ));
+
+
+ //
+ // Free the allocated memory before returning.
+ //
+
+ if (parametersPath.Buffer)
+ {
+ ExFreePool(parametersPath.Buffer);
+ }
+
+ if (parameters)
+ {
+ ExFreePool(parameters);
+ }
+}
+
+
+NDIS_STATUS
+SendProviderInitRequest(
+ PPROVIDER_INFO Provider
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Provider - pointer to a PROVIDER_INFO representing provider to initialize
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_INFO tmpProvider;
+ PPROVIDER_REQUEST providerRequest;
+ PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData;
+
+
+ DBGOUT ((2, "SendProviderInitRequest: enter"));
+
+
+ //
+ // Determine the DeviceIDBase to be used for this provider
+ //
+
+ Provider->DeviceIDBase = DeviceExtension->NdisTapiDeviceIDBase;
+
+ 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),
+ 'TAPI'
+ );
+
+
+ providerRequest->NdisRequest.RequestType = NdisRequestQueryInformation;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ OID_TAPI_PROVIDER_INITIALIZE;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ sizeof(NDIS_TAPI_PROVIDER_INITIALIZE);
+
+
+ providerRequest->Provider = Provider;
+
+
+ providerInitData =
+ (PNDIS_TAPI_PROVIDER_INITIALIZE) providerRequest->Data;
+
+ providerInitData->ulRequestID = 0;
+ providerInitData->ulDeviceIDBase = Provider->DeviceIDBase;
+
+
+ //
+ // Send the request
+ //
+
+ ndisStatus=
+ (*Provider->RequestProc)(
+ Provider->ProviderHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ DoProviderInitComplete (providerRequest);
+
+ ExFreePool (providerRequest);
+ }
+ else if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // Do nothing
+ //
+ }
+ else
+ {
+ // PnP: an error occured, clean up & act like this never happened
+ }
+
+ DBGOUT ((2, "SendProviderInitRequest: exit"));
+
+ return ndisStatus;
+}
+
+
+NDIS_STATUS
+SendProviderShutdown(
+ PPROVIDER_INFO Provider
+ )
+
+/*++
+
+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;
+ PPROVIDER_REQUEST providerRequest;
+
+
+ DBGOUT ((2, "SendProviderShutdown: enter"));
+
+
+
+ //
+ // Create a provider init request
+ //
+
+ providerRequest = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN) -
+ sizeof(ULONG),
+ 'TAPI'
+ );
+
+
+ providerRequest->NdisRequest.RequestType = NdisRequestSetInformation;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ OID_TAPI_PROVIDER_SHUTDOWN;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
+
+
+ providerRequest->Provider = Provider;
+
+ providerRequest->Data[0] = 0; // request ID, 0 = driver-initiated req
+
+
+ //
+ // Send the request
+ //
+
+ ndisStatus = (*Provider->RequestProc)(
+ Provider->ProviderHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+
+ //
+ // 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: exit"));
+
+ 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:
+
+ Assumes DeviceExtension->SpinLock held by caller
+
+--*/
+
+{
+ ULONG numDevices = 0;
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_INFO provider = DeviceExtension->Providers;
+
+
+ DBGOUT((2, "SyncInitAllProviders: enter"));
+
+
+ while (provider != NULL)
+ {
+ if (provider->Status == PROVIDER_STATUS_PENDING_INIT)
+ {
+ ndisStatus = SendProviderInitRequest (provider);
+
+ if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // Wait for completion routine to get called
+ //
+
+ KeWaitForSingleObject (&DeviceExtension->SyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PTIME) NULL
+ );
+ }
+ else if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ provider->Status == PROVIDER_STATUS_ONLINE;
+ }
+ else
+ {
+ provider->Status == PROVIDER_STATUS_OFFLINE;
+ }
+ }
+
+ provider = provider->Next;
+ }
+
+
+ //
+ // If here all providers (>= 1) initialized, so determine the total
+ // # of line devices currently in the list
+ //
+
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ numDevices += provider->NumDevices;
+
+ provider = provider->Next;
+ }
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTING)
+ {
+ DeviceExtension->NdisTapiNumDevices = numDevices;
+ }
+ else if ((DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) &&
+ (numDevices > DeviceExtension->NdisTapiNumDevices))
+ {
+ // PnP: need to send TAPI a reinit msg (or LINE_CREATE?)
+
+ DBGOUT((1, "SyncInitAllProviders: exceeded numDevs, must reinit"));
+ }
+
+
+ DBGOUT((2, "SyncInitAllProviders: exit"));
+
+ return TRUE;
+}
diff --git a/private/ntos/ndis/ndistapi/ndistapi.rc b/private/ntos/ndis/ndistapi/ndistapi.rc
new file mode 100644
index 000000000..a0f75325a
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 connection wrapper driver"
+#define VER_INTERNALNAME_STR "NDISTAPI.SYS"
+#define VER_ORIGINALFILENAME_STR "NDISTAPI.SYS"
+
+#include "common.ver"
diff --git a/private/ntos/ndis/ndistapi/ndistapi.src b/private/ntos/ndis/ndistapi/ndistapi.src
new file mode 100644
index 000000000..3a071870e
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.src
@@ -0,0 +1,7 @@
+NAME NDISTAPI.SYS
+DESCRIPTION 'NDISTAPI.SYS'
+EXPORTS
+ NdisTapiRegisterProvider
+ NdisTapiCompleteRequest
+ NdisTapiIndicateStatus
+ NdisTapiDeregisterProvider
diff --git a/private/ntos/ndis/ndistapi/private.h b/private/ntos/ndis/ndistapi/private.h
new file mode 100644
index 000000000..5129f0ac5
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/private.h
@@ -0,0 +1,251 @@
+/*++ BUILD Version: 0000 // Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ private.h
+
+Abstract:
+
+ Private definitions for NdisTapi.sys
+
+Author:
+
+ Dan Knudson (DanKn) 20-Feb-1994
+
+Revision History:
+
+--*/
+
+
+//
+// Various definitions
+//
+
+typedef enum _PROVIDER_STATUS
+{
+ PROVIDER_STATUS_ONLINE,
+ PROVIDER_STATUS_OFFLINE,
+ PROVIDER_STATUS_PENDING_INIT
+
+} PROVIDER_STATUS, *PPROVIDER_STATUS;
+
+
+typedef NDIS_STATUS (*REQUEST_PROC)(NDIS_HANDLE, PNDIS_REQUEST);
+
+
+typedef struct _PROVIDER_INFO
+{
+ PROVIDER_STATUS Status;
+
+ NDIS_HANDLE ProviderHandle;
+
+ REQUEST_PROC RequestProc;
+
+ ULONG ProviderID;
+
+ ULONG NumDevices;
+
+ ULONG DeviceIDBase;
+
+ struct _PROVIDER_INFO *Next;
+
+} PROVIDER_INFO, *PPROVIDER_INFO;
+
+
+typedef enum _NDISTAPI_STATUS
+{
+ NDISTAPI_STATUS_CONNECTED,
+ NDISTAPI_STATUS_DISCONNECTED,
+ NDISTAPI_STATUS_CONNECTING,
+ NDISTAPI_STATUS_DISCONNECTING
+
+} NDISTAPI_STATUS, *PNDISTAPI_STATUS;
+
+
+typedef struct _DEVICE_EXTENSION
+{
+ //
+ // The following are set only in DriverEntry and are not
+ // modified elsewhere
+ //
+
+ //
+ // Pointer to the NdisTapi device object
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+ //
+ // Length in bytes of the event data buf
+ //
+
+ ULONG EventDataQueueLength;
+
+ //
+ // Pointer to a circular event data buf
+ //
+
+ PCHAR EventData;
+
+
+
+ //
+ // Synchronizes access to the device extension following fields
+ //
+
+ KSPIN_LOCK SpinLock;
+
+ //
+ // Whether TAPI has the the connection wrapper open
+ //
+
+ NDISTAPI_STATUS Status;
+
+ //
+ // Event we use for synchronizing provider inits
+ //
+
+ KEVENT SyncEvent;
+
+ //
+ // The connection wrapper's device ID base as passed down by TAPI
+ // when it connected.
+ //
+
+ ULONG NdisTapiDeviceIDBase;
+
+ //
+ // The number of line devices we told told TAPI we supported when
+ // it opened us (some of which may not actually be online at any
+ // given time)
+ //
+
+ ULONG NdisTapiNumDevices;
+
+ //
+ // Whether we have an outstanding provider init request
+ //
+
+ BOOLEAN ProviderInitPending;
+
+ //
+ // Pointer to a list of registered providers. (Some may actually
+ // not be currently registered, but they were at one point so we've
+ // saved a placeholder for them should they come back online at some
+ // point.)
+ //
+
+ PPROVIDER_INFO Providers;
+
+ //
+ //
+ //
+
+ BOOLEAN CleanupWasInitiated;
+
+ //
+ // A special queue for QUERY/SET_INFO requests
+ //
+
+ KDEVICE_QUEUE DeviceQueue;
+
+
+
+ //
+ // Synchronizes access to the events buffer & related fields
+ //
+
+ KSPIN_LOCK EventSpinLock;
+
+ //
+ // Value return to provider for next NEWCALL msg
+ //
+
+ ULONG htCall;
+
+ //
+ // Outstanding get-events request
+ //
+
+ PIRP EventsRequestIrp;
+
+ //
+ // Pointer to next place to PUT event data (from provider)
+ //
+
+ PCHAR DataIn;
+
+ //
+ // Pointer to next place to GET event data (for user-mode request)
+ //
+
+ PCHAR DataOut;
+
+ //
+ // Number of valid events in queue
+ //
+
+ ULONG EventCount;
+
+
+ //
+ //
+ //
+
+ PFILE_OBJECT TapiSrvFileObject;
+
+ //
+ //
+ //
+
+ PFILE_OBJECT NCPAFileObject;
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+
+typedef struct _PROVIDER_REQUEST
+{
+ NDIS_REQUEST NdisRequest;
+
+ PPROVIDER_INFO Provider;
+
+ //
+ // This field is a placeholder for an NDIS_TAPI_XXX structure, the
+ // first ULONG of which is always a request ID.
+ //
+
+ ULONG Data[1];
+
+} PROVIDER_REQUEST, *PPROVIDER_REQUEST;
+
+
+//
+// Our global device extension
+//
+
+PDEVICE_EXTENSION DeviceExtension;
+
+
+
+#if DBG
+
+//
+// A var which determines the verboseness of the msgs printed by DBGOUT()
+//
+//
+
+ULONG NdisTapiDebugLevel = 0;
+
+//
+// DbgPrint wrapper
+//
+
+#define DBGOUT(arg) DbgPrt arg
+
+#else
+
+#define DBGOUT(arg)
+
+#endif
diff --git a/private/ntos/ndis/ndistapi/sources b/private/ntos/ndis/ndistapi/sources
new file mode 100644
index 000000000..7d876fe2c
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ John Rogers (JohnRo) 25-Oct-1991
+
+NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ndistapi
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=EXPORT_DRIVER
+
+INCLUDES=..\..\inc
+C_DEFINES= $(C_DEFINES)
+
+SOURCES=ndistapi.c \
+ ndistapi.rc
+
+DLLDEF=obj\*\ndistapi.def
+
+MSC_WARNING_LEVEL=/W3 /WX