/*++ 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); }