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
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);
|
|
}
|
|
|