454 lines
12 KiB
C
454 lines
12 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntos\tdi\isn\flt\driver.c
|
|
|
|
Abstract:
|
|
IPX Filter driver dispatch routines
|
|
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
PFILE_OBJECT RouterFile;
|
|
|
|
NTSTATUS
|
|
IpxFltDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
IpxFltUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
VOID
|
|
IpxFltCancel (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP irp
|
|
);
|
|
|
|
/*++
|
|
D r i v e r E n t r y
|
|
|
|
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
|
|
|
|
--*/
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
) {
|
|
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
NTSTATUS status;
|
|
UNICODE_STRING deviceNameUnicodeString;
|
|
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: Driver Entry.\n"));
|
|
|
|
RtlInitUnicodeString (&deviceNameUnicodeString,
|
|
IPXFLT_NAME);
|
|
|
|
status = IoCreateDevice (DriverObject,
|
|
0,
|
|
&deviceNameUnicodeString,
|
|
FILE_DEVICE_IPXFLT,
|
|
0,
|
|
FALSE, // Non-Exclusive
|
|
&deviceObject
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// Create dispatch points for device control, create, close.
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE]
|
|
= DriverObject->MajorFunction[IRP_MJ_CLEANUP]
|
|
= DriverObject->MajorFunction[IRP_MJ_CLOSE]
|
|
= DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
|
|
= IpxFltDispatch;
|
|
DriverObject->DriverUnload = IpxFltUnload;
|
|
status = BindToFwdDriver (KernelMode);
|
|
if (NT_SUCCESS (status)) {
|
|
RouterFile = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
IoDeleteDevice (DriverObject->DeviceObject);
|
|
}
|
|
}
|
|
else
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Could not create device object.\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
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
|
|
IpxFltDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
) {
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PVOID inBuffer, outBuffer;
|
|
ULONG inpBufLength;
|
|
ULONG outBufLength;
|
|
NTSTATUS status;
|
|
KIRQL cancelIRQL;
|
|
ULONG ulBytes;
|
|
|
|
ulBytes = 0;
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Get a pointer to the current location in the Irp. This is where
|
|
// the function codes and parameters are located.
|
|
//
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
|
switch (IrpStack->MajorFunction) {
|
|
case IRP_MJ_CREATE:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CREATE.\n"));
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CLOSE.\n"));
|
|
if (IrpStack->FileObject == RouterFile) {
|
|
DeleteTables ();
|
|
RouterFile = NULL;
|
|
}
|
|
break;
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CLEANUP.\n"));
|
|
if (IrpStack->FileObject==RouterFile) {
|
|
IoAcquireCancelSpinLock (&cancelIRQL);
|
|
while (!IsListEmpty (&LogIrpQueue)) {
|
|
PIRP irp = CONTAINING_RECORD (LogIrpQueue.Blink,
|
|
IRP, Tail.Overlay.ListEntry);
|
|
irp->Cancel = TRUE;
|
|
irp->CancelIrql = cancelIRQL;
|
|
irp->CancelRoutine = NULL;
|
|
IpxFltCancel(DeviceObject, irp);
|
|
IoAcquireCancelSpinLock (&cancelIRQL);
|
|
}
|
|
IoReleaseCancelSpinLock(cancelIRQL);
|
|
}
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
//
|
|
// Get the pointer to the input/output buffer and it's length
|
|
//
|
|
status = STATUS_INVALID_PARAMETER;
|
|
inpBufLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|
outBufLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode&3) {
|
|
case METHOD_BUFFERED:
|
|
inBuffer = outBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
break;
|
|
|
|
case METHOD_IN_DIRECT:
|
|
case METHOD_OUT_DIRECT:
|
|
inBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
if (outBufLength>0) {
|
|
outBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
|
|
if (outBuffer == NULL)
|
|
{
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS, ("IpxFlt: System out of PTE's.\n"));
|
|
goto DispatchExit;
|
|
}
|
|
}
|
|
else {
|
|
outBuffer = NULL;
|
|
}
|
|
break;
|
|
default:
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS, ("IpxFlt: Unsupported io method.\n"));
|
|
goto DispatchExit;
|
|
}
|
|
|
|
|
|
if (IrpStack->FileObject==RouterFile) {
|
|
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_FLT_IF_SET_IN_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_SET_IN_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (FLT_IF_SET_PARAMS))
|
|
&& (((PFLT_IF_SET_PARAMS)inBuffer)->FilterSize
|
|
==sizeof (IPX_TRAFFIC_FILTER_INFO)))
|
|
status = SetInFilters (
|
|
((PFLT_IF_SET_PARAMS)inBuffer)->InterfaceIndex,
|
|
((PFLT_IF_SET_PARAMS)inBuffer)->FilterAction,
|
|
outBufLength,
|
|
(PIPX_TRAFFIC_FILTER_INFO)outBuffer);
|
|
|
|
break;
|
|
|
|
case IOCTL_FLT_IF_SET_OUT_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_SET_OUT_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (FLT_IF_SET_PARAMS))
|
|
&& (((PFLT_IF_SET_PARAMS)inBuffer)->FilterSize
|
|
==sizeof (IPX_TRAFFIC_FILTER_INFO)))
|
|
status = SetOutFilters (
|
|
((PFLT_IF_SET_PARAMS)inBuffer)->InterfaceIndex,
|
|
((PFLT_IF_SET_PARAMS)inBuffer)->FilterAction,
|
|
outBufLength,
|
|
(PIPX_TRAFFIC_FILTER_INFO)outBuffer);
|
|
|
|
break;
|
|
case IOCTL_FLT_IF_RESET_IN_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_RESET_IN_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (ULONG))
|
|
&& (outBufLength==0))
|
|
status = SetInFilters (
|
|
*((PULONG)inBuffer),
|
|
IPX_TRAFFIC_FILTER_ACTION_DENY,
|
|
0, NULL);
|
|
|
|
break;
|
|
case IOCTL_FLT_IF_RESET_OUT_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_RESET_OUT_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (ULONG))
|
|
&& (outBufLength==0))
|
|
status = SetOutFilters (
|
|
*((PULONG)inBuffer),
|
|
IPX_TRAFFIC_FILTER_ACTION_DENY,
|
|
0, NULL);
|
|
|
|
break;
|
|
case IOCTL_FLT_IF_GET_IN_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_GET_IN_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (ULONG))
|
|
&& (outBufLength>=sizeof (FLT_IF_GET_PARAMS))) {
|
|
Irp->IoStatus.Information
|
|
= outBufLength-sizeof (FLT_IF_GET_PARAMS);
|
|
ulBytes = (ULONG)Irp->IoStatus.Information;
|
|
status = GetInFilters (
|
|
*((PULONG)inBuffer),
|
|
&((PFLT_IF_GET_PARAMS)outBuffer)->FilterAction,
|
|
&((PFLT_IF_GET_PARAMS)outBuffer)->TotalSize,
|
|
(PIPX_TRAFFIC_FILTER_INFO)
|
|
((PUCHAR)outBuffer+sizeof (FLT_IF_GET_PARAMS)),
|
|
&ulBytes);
|
|
Irp->IoStatus.Information = ulBytes;
|
|
if (NT_SUCCESS (status)) {
|
|
Irp->IoStatus.Information += sizeof (FLT_IF_GET_PARAMS);
|
|
((PFLT_IF_GET_PARAMS)outBuffer)->FilterSize
|
|
= sizeof (IPX_TRAFFIC_FILTER_INFO);
|
|
}
|
|
else
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
break;
|
|
case IOCTL_FLT_IF_GET_OUT_FILTERS:
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_GET_OUT_FILTERS.\n"));
|
|
if ((inpBufLength==sizeof (ULONG))
|
|
&& (outBufLength>=sizeof (FLT_IF_GET_PARAMS))) {
|
|
Irp->IoStatus.Information
|
|
= outBufLength-sizeof (FLT_IF_GET_PARAMS);
|
|
ulBytes = (ULONG)Irp->IoStatus.Information;
|
|
status = GetOutFilters (
|
|
*((PULONG)inBuffer),
|
|
&((PFLT_IF_GET_PARAMS)outBuffer)->FilterAction,
|
|
&((PFLT_IF_GET_PARAMS)outBuffer)->TotalSize,
|
|
(PIPX_TRAFFIC_FILTER_INFO)
|
|
((PUCHAR)outBuffer+sizeof (FLT_IF_GET_PARAMS)),
|
|
&ulBytes);
|
|
Irp->IoStatus.Information = ulBytes;
|
|
if (NT_SUCCESS (status)) {
|
|
Irp->IoStatus.Information += sizeof (FLT_IF_GET_PARAMS);
|
|
((PFLT_IF_GET_PARAMS)outBuffer)->FilterSize
|
|
= sizeof (IPX_TRAFFIC_FILTER_INFO);
|
|
}
|
|
else
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
break;
|
|
case IOCTL_FLT_GET_LOGGED_PACKETS:
|
|
IpxFltDbgPrint (DBG_PKTLOGS, ("IpxFlt: IOCTL_FLT_GET_LOGGED_PACKETS.\n"));
|
|
Irp->IoStatus.Status = status = STATUS_PENDING;
|
|
IoMarkIrpPending (Irp);
|
|
IoAcquireCancelSpinLock (&cancelIRQL);
|
|
InsertTailList (&LogIrpQueue,
|
|
&Irp->Tail.Overlay.ListEntry);
|
|
IoSetCancelRoutine (Irp, IpxFltCancel);
|
|
if (LogIrpQueue.Flink!=&Irp->Tail.Overlay.ListEntry) {
|
|
PIRP irp = CONTAINING_RECORD (
|
|
LogIrpQueue.Flink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry);
|
|
if (irp->IoStatus.Information>0) {
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
IoSetCancelRoutine (irp, NULL);
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoReleaseCancelSpinLock (cancelIRQL);
|
|
IpxFltDbgPrint (DBG_PKTLOGS,
|
|
("IpxFlt: completing logging request"
|
|
" with %d bytes of data.\n",
|
|
irp->IoStatus.Information));
|
|
IoCompleteRequest (irp, IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
}
|
|
IoReleaseCancelSpinLock (cancelIRQL);
|
|
break;
|
|
default:
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Unsupported IOCTL %lx.\n",
|
|
IrpStack->Parameters.DeviceIoControl.IoControlCode));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
else if (RouterFile==NULL) {
|
|
if (IrpStack->Parameters.DeviceIoControl.IoControlCode
|
|
==IOCTL_FLT_START) {
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_START.\n"));
|
|
status = InitializeTables ();
|
|
if (NT_SUCCESS (status)) {
|
|
RouterFile = IrpStack->FileObject;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Unsupported IOCTL %lx (driver is not started yet)).\n",
|
|
IrpStack->Parameters.DeviceIoControl.IoControlCode));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
}
|
|
else {
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Unsupported IOCTL %lx from non-router client.\n",
|
|
IrpStack->Parameters.DeviceIoControl.IoControlCode));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Unsupported function %lx.\n",
|
|
IrpStack->MajorFunction));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
DispatchExit:
|
|
if (status!=STATUS_PENDING) {
|
|
Irp->IoStatus.Status = status;
|
|
if (NT_SUCCESS (status))
|
|
;
|
|
else
|
|
IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
|
|
("IpxFlt: Failed call with status %lx.\n",
|
|
status));
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cleans up on driver unload
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to a driver object
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
VOID
|
|
IpxFltUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
) {
|
|
IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: Unloading\n"));
|
|
if (RouterFile!=NULL) {
|
|
DeleteTables ();
|
|
RouterFile = NULL;
|
|
}
|
|
UnbindFromFwdDriver (KernelMode);
|
|
IoDeleteDevice (DriverObject->DeviceObject);
|
|
}
|
|
|
|
|
|
/*++
|
|
I p x F l t C a n c e l
|
|
|
|
Routine Description:
|
|
Cancels specified IRP
|
|
|
|
Arguments:
|
|
DeviceObject - forwarder device object
|
|
irp - irp to cancel
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
VOID
|
|
IpxFltCancel (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP irp
|
|
) {
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
IoReleaseCancelSpinLock (irp->CancelIrql);
|
|
|
|
irp->IoStatus.Status = STATUS_CANCELLED;
|
|
IpxFltDbgPrint(DBG_IOCTLS, ("IpxFlt: completing cancelled irp.\n"));
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
}
|
|
|