mirror of https://github.com/lianthony/NT4.0
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.
1465 lines
34 KiB
1465 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
stubmp.c
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Author:
|
|
|
|
Dan Knudson (DanKn) 11-Apr-1995
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Revision History:
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
#include "ntddk.h"
|
|
//#include "ntos.h"
|
|
#include "ndismain.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "ndistapi.h"
|
|
#include "stubmp.h"
|
|
#include "intrface.h"
|
|
|
|
|
|
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
//ULONG StubmpDebugLevel = 3;
|
|
ULONG StubmpDebugLevel = 0;
|
|
|
|
#define DBGOUT(arg) DbgPrt arg
|
|
|
|
VOID
|
|
DbgPrt(
|
|
IN ULONG DbgLevel,
|
|
IN PUCHAR DbgMessage,
|
|
IN ...
|
|
);
|
|
|
|
#else
|
|
|
|
#define DBGOUT(arg)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
StubmpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NDIS_STATUS
|
|
StubmpRequest(
|
|
NDIS_HANDLE NdisBindingHandle,
|
|
PNDIS_REQUEST NdisRequest
|
|
);
|
|
|
|
VOID
|
|
StubmpUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
VOID
|
|
StubmpCancel(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
WriteRingBuffer(
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
);
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
ULONG i, ulNumLines = 4,
|
|
ulNumAddrsPerLine = 4,
|
|
ulNumCallsPerLine = 4;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
NTSTATUS ntStatus;
|
|
WCHAR deviceNameBuffer[] = L"\\Device\\Stubmp";
|
|
UNICODE_STRING deviceNameUnicodeString;
|
|
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\Stubmp";
|
|
UNICODE_STRING deviceLinkUnicodeString;
|
|
|
|
|
|
DBGOUT ((2, "DriverEntry: enter"));
|
|
|
|
|
|
//
|
|
// Create an EXCLUSIVE device, i.e. only 1 thread at a time can send
|
|
// i/o requests.
|
|
//
|
|
|
|
RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
|
|
|
|
ntStatus = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof(DEVICE_EXTENSION) + (ulNumLines - 1) * sizeof(PDRVLINE),
|
|
&deviceNameUnicodeString,
|
|
FILE_DEVICE_STUBMP,
|
|
0,
|
|
FALSE, // not exclusive
|
|
&deviceObject
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ULONG numBytesPerLine = sizeof(DRVLINE) +
|
|
(ulNumCallsPerLine - 1) * sizeof(DRVCALL);
|
|
|
|
DeviceExtension = (PDEVICE_EXTENSION)
|
|
deviceObject->DeviceExtension;
|
|
|
|
RtlZeroMemory (DeviceExtension, sizeof (DEVICE_EXTENSION));
|
|
|
|
DeviceExtension->CompleteAsync = TRUE;
|
|
|
|
DeviceExtension->ulNumLines = ulNumLines;
|
|
DeviceExtension->ulNumAddrsPerLine = ulNumAddrsPerLine;
|
|
DeviceExtension->ulNumCallsPerLine = ulNumCallsPerLine;
|
|
|
|
|
|
KeInitializeSpinLock (&DeviceExtension->EventSpinLock);
|
|
|
|
DeviceExtension->EventDataQueueLength = 1024;
|
|
|
|
DeviceExtension->EventDataQueue =
|
|
DeviceExtension->DataIn =
|
|
DeviceExtension->DataOut = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
DeviceExtension->EventDataQueueLength,
|
|
'TAPI'
|
|
);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
for (i = 0; i < ulNumLines; i++)
|
|
{
|
|
DeviceExtension->apLines[i] = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
numBytesPerLine,
|
|
'TAPI'
|
|
);
|
|
|
|
RtlZeroMemory (DeviceExtension->apLines[i], numBytesPerLine);
|
|
}
|
|
|
|
|
|
//
|
|
// Create a symbolic link that Win32 apps can specify to gain access
|
|
// to this driver/device
|
|
//
|
|
|
|
RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);
|
|
|
|
ntStatus = IoCreateSymbolicLink(
|
|
&deviceLinkUnicodeString,
|
|
&deviceNameUnicodeString
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGOUT ((0, "DriverEntry: IoCreateSymbolicLink failed"));
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Init dispatch points for device control, create, close.
|
|
//
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] =
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = StubmpDispatch;
|
|
DriverObject->DriverUnload = StubmpUnload;
|
|
}
|
|
|
|
|
|
done_DriverEntry:
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Something went wrong, so clean up (free resources, etc.)
|
|
//
|
|
|
|
if (deviceObject)
|
|
{
|
|
IoDeleteDevice (deviceObject);
|
|
}
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
StubmpDispatch(
|
|
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:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PVOID ioBuffer;
|
|
ULONG inputBufferLength;
|
|
ULONG outputBufferLength;
|
|
ULONG ioControlCode;
|
|
NTSTATUS ntStatus;
|
|
NDIS_TAPI_EVENT event;
|
|
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"));
|
|
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
|
|
DBGOUT ((2, "IRP_MJ_CLOSE"));
|
|
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
|
|
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
switch (ioControlCode)
|
|
{
|
|
case IOCTL_STUBMP_APPREQUEST:
|
|
{
|
|
PREQUESTBLOCK pRequestBlock = (PREQUESTBLOCK) ioBuffer;
|
|
|
|
|
|
DBGOUT ((2, "IOCTL_STUBMP_APPREQUEST"));
|
|
|
|
switch (pRequestBlock->ulRequestType)
|
|
{
|
|
case RT_REGISTER:
|
|
|
|
NdisTapiRegisterProvider(
|
|
(NDIS_HANDLE) 0x55,
|
|
(REQUEST_PROC) StubmpRequest
|
|
);
|
|
|
|
break;
|
|
|
|
case RT_DEREGISTER:
|
|
|
|
NdisTapiDeregisterProvider ((NDIS_HANDLE) 0x55);
|
|
|
|
break;
|
|
|
|
case RT_COMPLETEREQUEST:
|
|
{
|
|
ULONG *args = (ULONG *) (pRequestBlock->Data);
|
|
|
|
|
|
DBGOUT ((2, "completing req x%x", *args));
|
|
|
|
NdisTapiCompleteRequest(
|
|
(NDIS_HANDLE) 0x55,
|
|
(PNDIS_REQUEST) *args,
|
|
(NDIS_STATUS) *(args + 1)
|
|
);
|
|
|
|
break;
|
|
}
|
|
case RT_SYNCCOMPLETIONS:
|
|
|
|
DeviceExtension->CompleteAsync = FALSE;
|
|
break;
|
|
|
|
case RT_ASYNCCOMPLETIONS:
|
|
|
|
DeviceExtension->CompleteAsync = TRUE;
|
|
break;
|
|
|
|
case RT_INCOMINGCALL:
|
|
|
|
//BUGBUG
|
|
break;
|
|
|
|
case RT_EVENT:
|
|
|
|
//BUGBUG
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case IOCTL_STUBMP_GETEVENTS:
|
|
{
|
|
KIRQL oldIrql;
|
|
KIRQL cancelIrql;
|
|
BOOLEAN satisfiedRequest = FALSE;
|
|
|
|
|
|
//
|
|
// Sync event buf access by acquiring EventSpinLock
|
|
//
|
|
|
|
KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
|
|
|
|
|
|
//
|
|
// Inspect DeviceExtension to see if there's any data available
|
|
//
|
|
|
|
DBGOUT((
|
|
2,
|
|
"IOCTL_STUBMP_GETEVENTS, Irp=x%x, bytesInQ=x%x",
|
|
Irp,
|
|
DeviceExtension->BytesInQueue
|
|
));
|
|
|
|
if (DeviceExtension->BytesInQueue != 0)
|
|
{
|
|
ULONG bytesInQueue;
|
|
ULONG bytesToMove;
|
|
ULONG moveSize;
|
|
PCHAR EventBuffer = (PCHAR) ((ULONG *) ioBuffer + 1);
|
|
|
|
|
|
bytesInQueue = DeviceExtension->BytesInQueue;
|
|
|
|
bytesToMove = *((ULONG *) ioBuffer);
|
|
|
|
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->EventDataQueue +
|
|
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->EventDataQueue,
|
|
moveSize
|
|
);
|
|
|
|
//
|
|
// Update the class input data queue removal pointer.
|
|
//
|
|
|
|
DeviceExtension->DataOut =
|
|
((PCHAR) DeviceExtension->EventDataQueue) + moveSize;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update the input data queue removal pointer.
|
|
//
|
|
|
|
DeviceExtension->DataOut =
|
|
((PCHAR) DeviceExtension->DataOut) + moveSize;
|
|
}
|
|
|
|
|
|
//
|
|
// Update the event data queue EventCount.
|
|
//
|
|
|
|
DeviceExtension->BytesInQueue -= bytesToMove;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
*((ULONG *) ioBuffer) = bytesToMove;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(ULONG) + bytesToMove;
|
|
|
|
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, StubmpCancel);
|
|
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;
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// DON'T get cute and try to use the status field of
|
|
// the irp in the return status. That IRP IS GONE as
|
|
// soon as you call IoCompleteRequest.
|
|
//
|
|
|
|
ntStatus = Irp->IoStatus.Status;
|
|
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
|
|
//
|
|
// We never have pending operation so always return the status code.
|
|
//
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
PDRVLINE
|
|
GetpLine(
|
|
HDRV_LINE hdLine
|
|
)
|
|
{
|
|
return (DeviceExtension->apLines
|
|
[(ULONG) hdLine - DeviceExtension->DeviceIDBase]);
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
StubmpRequest(
|
|
NDIS_HANDLE NdisBindingHandle,
|
|
PNDIS_REQUEST NdisRequest
|
|
)
|
|
{
|
|
BOOLEAN completeAsync = DeviceExtension->CompleteAsync;
|
|
ULONG i, j, ulRequestSpecific = 0;
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
NDIS_TAPI_EVENT event;
|
|
|
|
|
|
//
|
|
// Handle the request
|
|
//
|
|
|
|
if (NdisRequest->RequestType == NdisRequestQueryInformation)
|
|
{
|
|
switch (NdisRequest->DATA.QUERY_INFORMATION.Oid)
|
|
{
|
|
case OID_TAPI_CONFIG_DIALOG:
|
|
{
|
|
PNDIS_TAPI_CONFIG_DIALOG pConfigDialog =
|
|
(PNDIS_TAPI_CONFIG_DIALOG)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_DEV_SPECIFIC:
|
|
{
|
|
PNDIS_TAPI_DEV_SPECIFIC pDevSpecific =
|
|
(PNDIS_TAPI_DEV_SPECIFIC)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_ADDRESS_CAPS:
|
|
{
|
|
PNDIS_TAPI_GET_ADDRESS_CAPS pGetAddressCaps =
|
|
(PNDIS_TAPI_GET_ADDRESS_CAPS)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_ADDRESS_ID:
|
|
{
|
|
PNDIS_TAPI_GET_ADDRESS_ID pGetAddressID =
|
|
(PNDIS_TAPI_GET_ADDRESS_ID)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_ADDRESS_STATUS:
|
|
{
|
|
PNDIS_TAPI_GET_ADDRESS_STATUS pGetAddressStatus =
|
|
(PNDIS_TAPI_GET_ADDRESS_STATUS)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_CALL_ADDRESS_ID:
|
|
{
|
|
PNDIS_TAPI_GET_CALL_ADDRESS_ID pGetCallAddressID =
|
|
(PNDIS_TAPI_GET_CALL_ADDRESS_ID)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_CALL_INFO:
|
|
{
|
|
PNDIS_TAPI_GET_CALL_INFO pGetCallInfo =
|
|
(PNDIS_TAPI_GET_CALL_INFO)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_CALL_STATUS:
|
|
{
|
|
PNDIS_TAPI_GET_CALL_STATUS pGetCallStatus =
|
|
(PNDIS_TAPI_GET_CALL_STATUS)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_DEV_CAPS:
|
|
{
|
|
PNDIS_TAPI_GET_DEV_CAPS pGetDevCaps = (PNDIS_TAPI_GET_DEV_CAPS)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_DEV_CONFIG:
|
|
{
|
|
PNDIS_TAPI_GET_DEV_CONFIG pGetDevConfig =
|
|
(PNDIS_TAPI_GET_DEV_CONFIG)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_EXTENSION_ID:
|
|
{
|
|
PNDIS_TAPI_GET_EXTENSION_ID pGetExtensionID =
|
|
(PNDIS_TAPI_GET_EXTENSION_ID)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_ID:
|
|
{
|
|
PNDIS_TAPI_GET_ID pGetID = (PNDIS_TAPI_GET_ID)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_GET_LINE_DEV_STATUS:
|
|
{
|
|
PNDIS_TAPI_GET_LINE_DEV_STATUS pGetLineDevStatus =
|
|
(PNDIS_TAPI_GET_LINE_DEV_STATUS)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_MAKE_CALL:
|
|
{
|
|
PNDIS_TAPI_MAKE_CALL pMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
PDRVLINE pLine = GetpLine (pMakeCall->hdLine);
|
|
|
|
|
|
for (i = 0; i < DeviceExtension->ulNumCallsPerLine; i++)
|
|
{
|
|
if (!pLine->aCalls[i].htCall)
|
|
{
|
|
pLine->aCalls[i].htCall = pMakeCall->htCall;
|
|
pLine->aCalls[i].pLine = pLine;
|
|
|
|
pMakeCall->hdCall = (HDRV_CALL) (pLine->aCalls + i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == DeviceExtension->ulNumCallsPerLine)
|
|
{
|
|
status = NDIS_STATUS_TAPI_CALLUNAVAIL;
|
|
}
|
|
|
|
ulRequestSpecific = (ULONG) (pLine->aCalls + i);
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_NEGOTIATE_EXT_VERSION:
|
|
{
|
|
PNDIS_TAPI_NEGOTIATE_EXT_VERSION pNegotiateExtVersion =
|
|
(PNDIS_TAPI_NEGOTIATE_EXT_VERSION)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_OPEN:
|
|
{
|
|
PNDIS_TAPI_OPEN pOpen = (PNDIS_TAPI_OPEN)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
PDRVLINE pLine = DeviceExtension->apLines
|
|
[pOpen->ulDeviceID - DeviceExtension->DeviceIDBase];
|
|
|
|
|
|
ulRequestSpecific =
|
|
pLine->htLine = pOpen->htLine;
|
|
|
|
pOpen->hdLine = (HDRV_LINE) pOpen->ulDeviceID;
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_PROVIDER_INITIALIZE:
|
|
{
|
|
PNDIS_TAPI_PROVIDER_INITIALIZE pInitialize =
|
|
(PNDIS_TAPI_PROVIDER_INITIALIZE)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
|
|
DeviceExtension->DeviceIDBase = pInitialize->ulDeviceIDBase;
|
|
|
|
for (i = 0; i < DeviceExtension->ulNumLines; i++)
|
|
{
|
|
DeviceExtension->apLines[i]->ulDeviceID =
|
|
pInitialize->ulDeviceIDBase + i;
|
|
|
|
for (j = 0; j < DeviceExtension->ulNumCallsPerLine; j++)
|
|
{
|
|
DeviceExtension->apLines[i]->aCalls[j].htCall =
|
|
(HTAPI_CALL) NULL;
|
|
}
|
|
}
|
|
|
|
ulRequestSpecific =
|
|
pInitialize->ulNumLineDevs = DeviceExtension->ulNumLines;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
|
|
//
|
|
// Send info about this request to the app
|
|
//
|
|
|
|
{
|
|
ULONG *args = (ULONG *)
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
ULONG requestData[8] =
|
|
{
|
|
ET_REQUEST,
|
|
(ULONG) completeAsync,
|
|
(ULONG) NdisRequest,
|
|
(ULONG) status,
|
|
(ULONG) NdisRequest->DATA.QUERY_INFORMATION.Oid,
|
|
*args,
|
|
*(args+1),
|
|
ulRequestSpecific
|
|
};
|
|
|
|
|
|
WriteRingBuffer (requestData, 8 * sizeof(ULONG));
|
|
}
|
|
}
|
|
|
|
else if (NdisRequest->RequestType == NdisRequestSetInformation)
|
|
{
|
|
switch (NdisRequest->DATA.SET_INFORMATION.Oid)
|
|
{
|
|
case OID_TAPI_ACCEPT:
|
|
{
|
|
PNDIS_TAPI_ACCEPT pAccept = (PNDIS_TAPI_ACCEPT)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_ANSWER:
|
|
{
|
|
PNDIS_TAPI_ANSWER pAnswer = (PNDIS_TAPI_ANSWER)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_CLOSE:
|
|
{
|
|
PNDIS_TAPI_CLOSE pClose = (PNDIS_TAPI_CLOSE)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
PDRVLINE pLine = GetpLine (pClose->hdLine);
|
|
|
|
|
|
pLine->htLine = 0;
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_CLOSE_CALL:
|
|
{
|
|
PNDIS_TAPI_CLOSE_CALL pCloseCall = (PNDIS_TAPI_CLOSE_CALL)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
PDRVCALL pCall = (PDRVCALL) pCloseCall->hdCall;
|
|
|
|
|
|
pCall->htCall = (HTAPI_CALL) NULL;
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_CONDITIONAL_MEDIA_DETECTION:
|
|
{
|
|
PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION pConditionalMediaDetection =
|
|
(PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_DIAL:
|
|
{
|
|
PNDIS_TAPI_DIAL pDial = (PNDIS_TAPI_DIAL)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_DROP:
|
|
{
|
|
PNDIS_TAPI_DROP pDrop = (PNDIS_TAPI_DROP)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_PROVIDER_SHUTDOWN:
|
|
{
|
|
PNDIS_TAPI_PROVIDER_SHUTDOWN pShutdown =
|
|
(PNDIS_TAPI_PROVIDER_SHUTDOWN)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SECURE_CALL:
|
|
{
|
|
PNDIS_TAPI_SECURE_CALL pSecureCall = (PNDIS_TAPI_SECURE_CALL)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SELECT_EXT_VERSION:
|
|
{
|
|
PNDIS_TAPI_SELECT_EXT_VERSION pSelectExtVersion =
|
|
(PNDIS_TAPI_SELECT_EXT_VERSION)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SEND_USER_USER_INFO:
|
|
{
|
|
PNDIS_TAPI_SEND_USER_USER_INFO pSendUserUserInfo =
|
|
(PNDIS_TAPI_SEND_USER_USER_INFO)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_APP_SPECIFIC:
|
|
{
|
|
PNDIS_TAPI_SET_APP_SPECIFIC pSetApSpecific =
|
|
(PNDIS_TAPI_SET_APP_SPECIFIC)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_CALL_PARAMS:
|
|
{
|
|
PNDIS_TAPI_SET_CALL_PARAMS pSetCallParams =
|
|
(PNDIS_TAPI_SET_CALL_PARAMS)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_DEFAULT_MEDIA_DETECTION:
|
|
{
|
|
PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION pSetDefaultMediaDetection =
|
|
(PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_DEV_CONFIG:
|
|
{
|
|
PNDIS_TAPI_SET_DEV_CONFIG pSetDevConfig =
|
|
(PNDIS_TAPI_SET_DEV_CONFIG)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_MEDIA_MODE:
|
|
{
|
|
PNDIS_TAPI_SET_MEDIA_MODE pSetMediaMode =
|
|
(PNDIS_TAPI_SET_MEDIA_MODE)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
case OID_TAPI_SET_STATUS_MESSAGES:
|
|
{
|
|
PNDIS_TAPI_SET_STATUS_MESSAGES pSetStatusMessages =
|
|
(PNDIS_TAPI_SET_STATUS_MESSAGES)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
|
|
//
|
|
// Send info about this request to the app
|
|
//
|
|
|
|
{
|
|
ULONG *args = (ULONG *)
|
|
NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
REQUEST_PARAMS requestParams =
|
|
{
|
|
ET_REQUEST,
|
|
(ULONG) completeAsync,
|
|
(ULONG) NdisRequest,
|
|
(ULONG) status,
|
|
(ULONG) NdisRequest->DATA.SET_INFORMATION.Oid,
|
|
*args,
|
|
*(args+1),
|
|
ulRequestSpecific
|
|
};
|
|
|
|
|
|
WriteRingBuffer (&requestParams, sizeof(REQUEST_PARAMS));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGOUT((1, "StubmpRequest: unknown NdisRequest->RequestType"));
|
|
}
|
|
|
|
|
|
if (completeAsync)
|
|
{
|
|
status = NDIS_STATUS_PENDING;
|
|
|
|
DBGOUT((2, "StubmpRequest: Req x%x pending", NdisRequest));
|
|
}
|
|
else
|
|
{
|
|
DBGOUT((2, "StubmpRequest: Req x%x completing sync", NdisRequest));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
StubmpUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free all the allocated resources, etc.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to a driver object
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\Stubmp";
|
|
UNICODE_STRING deviceLinkUnicodeString;
|
|
|
|
|
|
DBGOUT ((2, "StubmpUnload: enter"));
|
|
|
|
|
|
//
|
|
// Delete the symbolic link
|
|
//
|
|
|
|
RtlInitUnicodeString (&deviceLinkUnicodeString,
|
|
deviceLinkBuffer
|
|
);
|
|
|
|
IoDeleteSymbolicLink (&deviceLinkUnicodeString);
|
|
|
|
|
|
//
|
|
// Free all the resources
|
|
//
|
|
|
|
for (i = 0; i < DeviceExtension->ulNumLines; i++)
|
|
{
|
|
ExFreePool (DeviceExtension->apLines[i]);
|
|
}
|
|
|
|
|
|
//
|
|
// Delete the device object
|
|
//
|
|
|
|
IoDeleteDevice (DriverObject->DeviceObject);
|
|
}
|
|
|
|
|
|
VOID
|
|
StubmpCancel(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
|
|
DBGOUT((2,"StubmpCancel: 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);
|
|
|
|
|
|
StubmpCancel_done:
|
|
|
|
//
|
|
// Complete the request with STATUS_CANCELLED.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
DBGOUT((2,"StubmpCancel: exit (completing irp=x%x)", Irp));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef 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 <= StubmpDebugLevel)
|
|
{
|
|
char buf[256] = "STUBMP.SYS: ";
|
|
va_list ap;
|
|
|
|
va_start (ap, DbgMessage);
|
|
|
|
vsprintf (&buf[12], DbgMessage, ap);
|
|
|
|
strcat (buf, "\n");
|
|
|
|
DbgPrint (buf);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
WriteRingBuffer(
|
|
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;
|
|
PCHAR ioBuffer;
|
|
|
|
|
|
DBGOUT((2,"WriteRingBuffer: enter"));
|
|
|
|
bytesInQueue = StatusBufferSize;
|
|
|
|
moveSize = 0;
|
|
|
|
|
|
//
|
|
// Sync event buf access by acquiring EventSpinLock
|
|
//
|
|
|
|
KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
|
|
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
ioBuffer = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
bytesToMove = *((ULONG *) ioBuffer);
|
|
|
|
moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
|
|
|
|
RtlMoveMemory (
|
|
ioBuffer + sizeof(ULONG),
|
|
(PCHAR) StatusBuffer,
|
|
moveSize
|
|
);
|
|
|
|
|
|
//
|
|
// Set the flag so that we start the next packet and complete
|
|
// this read request (with STATUS_SUCCESS) prior to return.
|
|
//
|
|
|
|
*((ULONG *) ioBuffer) = moveSize;
|
|
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
irp->IoStatus.Information = sizeof(ULONG) + moveSize;
|
|
|
|
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->BytesInQueue;
|
|
|
|
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,"WriteRingBuffer: 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->EventDataQueue +
|
|
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->EventDataQueue +
|
|
DeviceExtension->EventDataQueueLength))
|
|
{
|
|
DeviceExtension->DataIn =
|
|
DeviceExtension->EventDataQueue;
|
|
}
|
|
|
|
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->BytesInQueue += bytesToMove;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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, "WriteRingBuffer: completing req x%x", irp));
|
|
}
|
|
|
|
|
|
DBGOUT((2,"WriteRingBuffer: exit"));
|
|
|
|
return;
|
|
}
|