www.pudn.com > tdi_fw.zip > tdi_fw.c


// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs) 
// 
// $Id: tdi_fw.c,v 1.7 2002/12/03 12:14:28 dev Exp $ 
 
/* 
 * Simple TDI-based personal firewall 
 */ 
 
#include  
#include  
#include "sock.h" 
 
#include "dispatch.h" 
#include "filter.h" 
#include "memtrack.h" 
#include "obj_tbl.h" 
#include "tdi_fw.h" 
 
#define IOCTL_TRANSFER_TYPE(ioctl)	((ioctl) & 3) 
 
/* context for tdi_skip_complete */ 
typedef struct { 
    PIO_COMPLETION_ROUTINE	old_cr;			/* old (original) completion routine */ 
    PVOID					old_context;	/* old (original) parameter for old_cr */ 
    PIO_COMPLETION_ROUTINE	new_cr;			/* new (replaced) completion routine */ 
	PVOID					new_context;	/* new (replaced) parameter for new_cr */ 
	PFILE_OBJECT			fileobj;		/* FileObject from IO_STACK_LOCATION */ 
	PDEVICE_OBJECT			new_devobj;		/* filter device object */ 
	UCHAR					old_control;	/* old (original) irps->Control */ 
} TDI_SKIP_CTX; 
 
/* prototypes */ 
 
static NTSTATUS	DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp); 
static VOID		OnUnload(IN PDRIVER_OBJECT DriverObject); 
 
#ifndef USE_TDI_HOOKING 
static NTSTATUS	c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj, 
							 PDEVICE_OBJECT *oldobj, wchar_t *devname); 
static void		d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj, 
							 PDEVICE_OBJECT fltobj); 
#else 
static NTSTATUS	hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook); 
static NTSTATUS	get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj); 
#endif 
 
static NTSTATUS	tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); 
 
/* device objects for: */ 
PDEVICE_OBJECT 
	g_tcpfltobj = NULL,		// \Device\Tcp 
	g_udpfltobj = NULL,		// \Device\Udp 
	g_ipfltobj = NULL,		// \Device\RawIp 
	g_devcontrol = NULL;	// control device 
 
ULONG g_got_control = 0;	// got control app (contains pid) 
 
#ifndef USE_TDI_HOOKING 
// original device objects 
PDEVICE_OBJECT g_tcpoldobj, g_udpoldobj, g_ipoldobj; 
#else 
// original driver object 
DRIVER_OBJECT g_old_DriverObject; 
BOOLEAN g_hooked = FALSE; 
#endif 
 
/* initialization */ 
NTSTATUS 
DriverEntry(IN PDRIVER_OBJECT theDriverObject, 
            IN PUNICODE_STRING theRegistryPath) 
{ 
    NTSTATUS status = STATUS_SUCCESS; 
	int i; 
	UNICODE_STRING name, linkname; 
 
	memtrack_init(); 
 
#ifdef USE_TDI_HOOKING 
	KdPrint(("[tdi_fw] WARNING! Using unstable working mode: TDI hooking!\n")); 
#endif 
 
	status = ot_init(); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: ot_init: 0x%x\n", status)); 
		goto done; 
	} 
 
	status = filter_init(); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: filter_init: 0x%x\n", status)); 
		goto done; 
	} 
	 
	for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) 
		theDriverObject->MajorFunction[i] = DeviceDispatch; 
 
#if DBG 
	// register UnLoad procedure 
	theDriverObject->DriverUnload = OnUnload; 
#endif 
 
	/* create control device and symbolic link */ 
 
	RtlInitUnicodeString(&name, L"\\Device\\tdi_fw"); 
 
	status = IoCreateDevice(theDriverObject, 
							0, 
							&name, 
							0, 
							0, 
							TRUE,		// exclusive! only one control app! 
							&g_devcontrol); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(control): 0x%x!\n", status)); 
		goto done; 
	} 
 
	RtlInitUnicodeString(&linkname, L"\\??\\tdi_fw"); 
 
	status = IoCreateSymbolicLink(&linkname, &name); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status)); 
		goto done; 
	} 
 
#ifndef USE_TDI_HOOKING 
 
	status = c_n_a_device(theDriverObject, &g_tcpfltobj, &g_tcpoldobj, L"\\Device\\Tcp"); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); 
		goto done; 
	} 
 
	status = c_n_a_device(theDriverObject, &g_udpfltobj, &g_udpoldobj, L"\\Device\\Udp"); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); 
		goto done; 
	} 
 
	status = c_n_a_device(theDriverObject, &g_ipfltobj, &g_ipoldobj, L"\\Device\\RawIp"); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); 
		goto done; 
	} 
 
#else	/* USE_TDI_HOOKING */ 
 
	/* get device objects for tcp/udp/ip */ 
 
	status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(tcp): 0x%x\n", status)); 
		goto done; 
	} 
	 
	status = get_device_object(L"\\Device\\Udp", &g_udpfltobj); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(udp): 0x%x\n", status)); 
		goto done; 
	} 
	 
	status = get_device_object(L"\\Device\\RawIp", &g_ipfltobj); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(ip): 0x%x\n", status)); 
		goto done; 
	} 
 
	/* hook tcpip */ 
 
	status = hook_tcpip(&g_old_DriverObject, TRUE); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: hook_driver: 0x%x\n", status)); 
		goto done; 
	} 
	g_hooked = TRUE; 
 
#endif	/* USE_TDI_HOOKING */ 
 
	status = STATUS_SUCCESS; 
 
done: 
	if (status != STATUS_SUCCESS) { 
		// cleanup 
		OnUnload(theDriverObject); 
	} 
 
    return status; 
} 
 
/* deinitialization */ 
VOID 
OnUnload(IN PDRIVER_OBJECT DriverObject) 
{ 
#ifndef USE_TDI_HOOKING 
	d_n_d_device(DriverObject, g_tcpoldobj, g_tcpfltobj); 
	d_n_d_device(DriverObject, g_udpoldobj, g_udpfltobj); 
	d_n_d_device(DriverObject, g_ipoldobj, g_ipfltobj); 
#else 
	if (g_hooked) 
		hook_tcpip(&g_old_DriverObject, FALSE);   
#endif 
 
	// delete control device and symbolic link 
	if (g_devcontrol != NULL) { 
		UNICODE_STRING linkname; 
		 
		RtlInitUnicodeString(&linkname, L"\\??\\tdi_fw"); 
		IoDeleteSymbolicLink(&linkname); 
 
		IoDeleteDevice(g_devcontrol); 
	} 
 
	filter_free(); 
	ot_free(); 
 
	memtrack_free(); 
} 
 
#ifndef USE_TDI_HOOKING 
 
/* create & attach device */ 
NTSTATUS 
c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj, PDEVICE_OBJECT *oldobj, 
			 wchar_t *devname) 
{ 
	NTSTATUS status; 
	UNICODE_STRING str; 
 
	/* create filter device */ 
 
	status = IoCreateDevice(DriverObject, 
							0, 
							NULL, 
							FILE_DEVICE_UNKNOWN, 
							0, 
							TRUE, 
							fltobj); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] c_n_a_device: IoCreateDevice(%S): 0x%x\n", devname, status)); 
		return status; 
	} 
 
	(*fltobj)->Flags |= DO_DIRECT_IO; 
 
	RtlInitUnicodeString(&str, devname); 
	 
	status = IoAttachDevice(*fltobj, &str, oldobj); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] DriverEntry: IoAttachDevice(%S): 0x%x\n", devname, status)); 
		return status; 
	} 
 
	KdPrint(("[tdi_fw] DriverEntry: %S fileobj: 0x%x\n", devname, *fltobj)); 
 
	return STATUS_SUCCESS; 
} 
 
/* detach & delete device */ 
void 
d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj, PDEVICE_OBJECT fltobj) 
{ 
	/* 
	 * Detaching of a filter driver at runtime is a high-risk deal 
	 */ 
 
#if 1 
	// for extremal guys only! 
	if (oldobj != NULL && fltobj != NULL) { 
		int i; 
		for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) 
			DriverObject->MajorFunction[i] = g_tcpoldobj->DriverObject->MajorFunction[i]; 
	} 
#endif 
 
	if (oldobj != NULL) 
		IoDetachDevice(oldobj); 
 
	if (fltobj != NULL) 
		IoDeleteDevice(fltobj); 
} 
 
#else	/* USE_TDI_HOOKING */ 
 
/* hook/unhook driver */ 
NTSTATUS 
hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook) 
{ 
	UNICODE_STRING drv_name; 
	NTSTATUS status; 
	PDRIVER_OBJECT new_DriverObject; 
	int i; 
 
	RtlInitUnicodeString(&drv_name, L"\\Driver\\Tcpip"); 
 
	status = ObReferenceObjectByName(&drv_name, OBJ_CASE_INSENSITIVE, NULL, 0, 
		IoDriverObjectType, KernelMode, NULL, &new_DriverObject); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] hook_driver: ObReferenceObjectByName\n")); 
		return status; 
	} 
 
	for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { 
		if (b_hook) { 
			old_DriverObject->MajorFunction[i] = new_DriverObject->MajorFunction[i]; 
			new_DriverObject->MajorFunction[i] = DeviceDispatch; 
		} else 
			new_DriverObject->MajorFunction[i] = old_DriverObject->MajorFunction[i]; 
	} 
	 
	return STATUS_SUCCESS;	 
} 
 
/* get device object by its name */ 
NTSTATUS 
get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj) 
{ 
	UNICODE_STRING str; 
	OBJECT_ATTRIBUTES oa; 
	NTSTATUS status; 
	HANDLE handle = NULL; 
	IO_STATUS_BLOCK isb; 
	PFILE_OBJECT fileobj; 
 
	// !!! this is UGLY way but I don't know the shortest one 
 
	RtlInitUnicodeString(&str, name); 
	InitializeObjectAttributes(&oa, &str, OBJ_CASE_INSENSITIVE, 0, 0); 
 
	status = ZwCreateFile(&handle, 0, &oa, &isb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, 
		0, NULL, 0); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] get_device_object: ZwCreateFile: 0x%x\n")); 
		goto done; 
	} 
	 
	status = ObReferenceObjectByHandle(handle, GENERIC_READ | GENERIC_WRITE, NULL, 
		KernelMode, &fileobj, NULL); 
	if (status != STATUS_SUCCESS) { 
		KdPrint(("[tdi_fw] get_device_object: ObReferenceObjectByHandle: 0x%x\n")); 
		goto done; 
	} 
	 
	// and get DeviceObject by FileObject 
	*devobj = fileobj->DeviceObject; 
 
	ObDereferenceObject(fileobj); 
 
	KdPrint(("[tdi_fw] get_device_object: \"%S\" devobj: 0x%x\n", name, *devobj)); 
 
done: 
	if (handle != NULL) 
		ZwClose(handle); 
 
	return status; 
} 
 
#endif	/* USE_TDI_HOOKING */ 
 
/* dispatch */ 
NTSTATUS 
DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp) 
{ 
	PIO_STACK_LOCATION irps; 
	NTSTATUS status; 
 
	// sanity check 
	if (irp == NULL) { 
		KdPrint(("[tdi_fw] DeviceDispatch: !irp\n")); 
		return STATUS_SUCCESS; 
	} 
	 
	irps = IoGetCurrentIrpStackLocation(irp); 
 
	if (DeviceObject == g_tcpfltobj || DeviceObject == g_udpfltobj || 
		DeviceObject == g_ipfltobj) { 
 
		/* 
		 * This IRP is for filtered device 
		 */ 
 
		int result; 
		struct completion completion; 
 
		memset(&completion, 0, sizeof(completion)); 
 
		// Analyze MajorFunction 
		switch (irps->MajorFunction) { 
 
		case IRP_MJ_CREATE:		/* create fileobject */ 
			 
			result = tdi_create(irp, irps, &completion); 
 
			status = tdi_dispatch_complete(DeviceObject, irp, result, 
				completion.routine, completion.context); 
			 
			break; 
 
		case IRP_MJ_DEVICE_CONTROL: 
			 
			KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_DEVICE_CONTROL, minor 0x%x for 0x%08X\n", 
				irps->MinorFunction, irps->FileObject)); 
 
			if (KeGetCurrentIrql() == PASSIVE_LEVEL) { 
				/* 
				 * try to convert it to IRP_MJ_INTERNAL_DEVICE_CONTROL 
				 * (works on PASSIVE_LEVEL only!) 
				 */ 
				status = TdiMapUserRequest(DeviceObject, irp, irps); 
			 
			} else 
				status = STATUS_NOT_IMPLEMENTED; // set fake status 
 
			if (status != STATUS_SUCCESS) { 
				// send IRP to original driver 
				status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL); 
				break; 
			} 
 
			// don't break! go to internal device control! 
		 
		case IRP_MJ_INTERNAL_DEVICE_CONTROL: { 
			/* 
			 * Analyze ioctl for TDI driver 
			 */ 
			int i; 
 
			for (i = 0; g_tdi_ioctls[i].MinorFunction != 0; i++) 
				if (g_tdi_ioctls[i].MinorFunction == irps->MinorFunction) { 
					 
#if DBG 
					// print description 
					KdPrint(("[tdi_fw] DeviceDispatch: %s (0x%x) for 0x%x\n", 
						g_tdi_ioctls[i].desc, 
						irps->MinorFunction, 
						irps->FileObject)); 
#endif 
 
					if (g_tdi_ioctls[i].fn == NULL) { 
						// send IRP to original driver 
						status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, 
							NULL, NULL); 
						break; 
					} 
 
					// call dispatch function 
 
					result = g_tdi_ioctls[i].fn(irp, irps, &completion); 
 
					// complete request 
					status = tdi_dispatch_complete(DeviceObject, irp, result, 
						completion.routine, completion.context); 
 
					break; 
				} 
	 
			// if dispatch function hasn't been found 
			if (g_tdi_ioctls[i].MinorFunction == 0) { 
				// send IRP to original driver 
				status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL); 
			} 
 
			break; 
		} 
 
		case IRP_MJ_CLEANUP:		/* cleanup fileobject */ 
 
			result = tdi_cleanup(irp, irps, &completion); 
 
			status = tdi_dispatch_complete(DeviceObject, irp, result, 
				completion.routine, completion.context); 
			break; 
 
		case IRP_MJ_CLOSE: 
			KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_CLOSE fileobj 0x%x\n", irps->FileObject)); 
 
			// passthrough IRP 
			status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, 
				completion.routine, completion.context); 
 
			break; 
 
		default: 
			KdPrint(("[tdi_fw] DeviceDispatch: major 0x%x, minor 0x%x for 0x%x\n", 
				irps->MajorFunction, irps->MinorFunction, irps->FileObject)); 
 
			// passthrough IRP 
			status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, 
				completion.routine, completion.context); 
		} 
 
	} else if (DeviceObject == g_devcontrol) { 
 
		/* 
		 * this IRP is for control object 
		 */ 
 
		// set default status 
		status = STATUS_SUCCESS; 
 
		if (irps->MajorFunction == IRP_MJ_CREATE) { 
 
			// initialize for user-mode part (exclusive access - 1 user-mode part) 
			filter_init_2(); 
 
			g_got_control = (ULONG)PsGetCurrentProcessId(); 
 
		} else if (irps->MajorFunction == IRP_MJ_CLOSE) { 
 
			// cleanup for user-mode part 
			filter_free_2(); 
 
			g_got_control = 0; 
 
		} if (irps->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 
 
			/* 
			 * control request 
			 */ 
 
			ULONG ioctl = irps->Parameters.DeviceIoControl.IoControlCode, 
				len = irps->Parameters.DeviceIoControl.InputBufferLength, 
				size = irps->Parameters.DeviceIoControl.OutputBufferLength; 
			char *out_buf; 
 
			if (IOCTL_TRANSFER_TYPE(ioctl) == METHOD_NEITHER) { 
				// this type of transfer unsupported 
				out_buf = NULL; 
			} else 
				out_buf = (char *)irp->AssociatedIrp.SystemBuffer; 
 
			// process control request 
			status = process_request(ioctl, out_buf, &len, size); 
 
			irp->IoStatus.Information = len; 
 
		} else 
			status = STATUS_SUCCESS; 
 
		irp->IoStatus.Status = status; 
 
		IoCompleteRequest(irp, IO_NO_INCREMENT); 
 
	} else { 
 
		KdPrint(("[tdi_fw] DeviceDispatch: ioctl for unknown DeviceObject 0x%x\n", DeviceObject)); 
 
#ifndef USE_TDI_HOOKING 
		// ??? just complete IRP 
		status = irp->IoStatus.Status = STATUS_SUCCESS; 
		IoCompleteRequest(irp, IO_NO_INCREMENT); 
#else 
		// call original handler 
		status = g_old_DriverObject.MajorFunction[irps->MajorFunction]( 
			DeviceObject, irp); 
#endif 
	} 
 
	return status; 
} 
 
/* 
 * Dispatch routines call this function to complete their processing. 
 * They _MUST_ call this function anyway. 
 */ 
NTSTATUS 
tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter, 
					  PIO_COMPLETION_ROUTINE cr, PVOID context) 
{ 
	PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp); 
	NTSTATUS status; 
 
	if (filter == FILTER_DENY) { 
		 
		/* 
		 * DENY: complete request with status "Access violation" 
		 */ 
 
		KdPrint(("[tdi_fw] tdi_dispatch_complete: [DROP!]" 
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n", 
			irps->MajorFunction, 
			irps->MinorFunction, 
			devobj, 
			irps->FileObject)); 
 
		status = irp->IoStatus.Status = STATUS_ACCESS_VIOLATION; 
		IoCompleteRequest (irp, IO_NO_INCREMENT); 
		 
	} else if (filter == FILTER_ALLOW) { 
 
		/* 
		 * ALLOW: pass IRP to the next driver 
		 */ 
 
#ifndef USE_TDI_HOOKING 
 
		PDEVICE_OBJECT old_devobj = get_original_devobj(devobj, NULL); 
 
		if (old_devobj == NULL) { 
			KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: Unknown DeviceObject 0x%x!\n", devobj)); 
	 
			status = irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 
			IoCompleteRequest (irp, IO_NO_INCREMENT); 
			 
			return status; 
		} 
 
#endif 
 
		KdPrint(("[tdi_fw] tdi_dispatch_complete: [ALLOW.]" 
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n", 
			irps->MajorFunction, 
			irps->MinorFunction, 
			devobj, 
			irps->FileObject)); 
 
#ifndef USE_TDI_HOOKING 
 
		if (cr == NULL || irp->CurrentLocation <= 1) { 
			/* 
			 * we use _THIS_ way of sending IRP to old driver 
			 * a) to avoid NO_MORE_STACK_LOCATIONS 
			 * b) and if we haven't our completions - no need to copy stack locations! 
			 */ 
 
			// stay on this location after IoCallDriver 
			IoSkipCurrentIrpStackLocation(irp); 
 
#endif 
 
			if (cr != NULL) { 
				/* 
				 * set completion routine (this way is slow) 
				 */ 
 
				// save old completion routine and context 
				TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)malloc_np(sizeof(*ctx)); 
				if (ctx == NULL) { 
					KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: malloc_np\n")); 
					 
					status = irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
					IoCompleteRequest(irp, IO_NO_INCREMENT); 
					 
					return status; 
				} 
 
				ctx->old_cr = irps->CompletionRoutine; 
				ctx->old_context = irps->Context; 
				ctx->new_cr = cr; 
				ctx->new_context = context; 
				ctx->fileobj = irps->FileObject; 
				ctx->new_devobj = devobj; 
				ctx->old_control = IoGetNextIrpStackLocation(irp)->Control; 
 
#ifndef USE_TDI_HOOKING 
				IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE); 
#else 
				// set completion for current irps 
				irps->CompletionRoutine = tdi_skip_complete; 
				irps->Context = ctx; 
				irps->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; 
#endif 
			} 
 
#ifndef USE_TDI_HOOKING			 
		} else { 
			PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp), 
				next_irps = IoGetNextIrpStackLocation(irp); 
			 
			memcpy(next_irps, irps, sizeof(*irps)); 
 
			if (cr != NULL) { 
				/* 
				 * this way for completion is more quicker then used above 
				 */ 
 
				IoSetCompletionRoutine(irp, cr, context, TRUE, TRUE, TRUE); 
			} else 
				IoSetCompletionRoutine(irp, tdi_generic_complete, NULL, TRUE, TRUE, TRUE); 
		} 
#endif 
 
		/* call original driver */ 
 
#ifndef USE_TDI_HOOKING 
		status = IoCallDriver(old_devobj, irp); 
#else 
		status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp); 
#endif 
 
	} else {	/* FILTER_UNKNOWN */ 
 
		/* 
		 * UNKNOWN: just complete the request 
		 */ 
 
		status = irp->IoStatus.Status = STATUS_SUCCESS;	// ??? 
		IoCompleteRequest (irp, IO_NO_INCREMENT); 
	} 
 
	return status; 
} 
 
/* 
 * completion routine for case if we use IoSkipCurrentIrpStackLocation way 
 * or we USE_TDI_HOOKING 
 */ 
NTSTATUS 
tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 
{ 
	TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)Context; 
	NTSTATUS status; 
	PIO_STACK_LOCATION irps; 
 
	if (Irp->IoStatus.Status != STATUS_SUCCESS) 
		KdPrint(("[tdi_fw] tdi_skip_complete: status 0x%x\n", Irp->IoStatus.Status)); 
 
	// restore IRP for using in our completion 
 
	Irp->CurrentLocation--; 
	Irp->Tail.Overlay.CurrentStackLocation--; 
 
	irps = IoGetCurrentIrpStackLocation(Irp); 
 
	KdPrint(("[tdi_fw] tdi_skip_complete: DeviceObject = 0x%x; FileObject = 0x%x\n", 
		DeviceObject, irps->FileObject)); 
 
	DeviceObject = irps->DeviceObject; 
 
	if (ctx->new_cr != NULL) { 
		// restore fileobject (it's NULL) 
		irps->FileObject = ctx->fileobj; 
		// set new device object in irps 
		irps->DeviceObject = ctx->new_devobj; 
		 
		// call new completion  
		status = ctx->new_cr(ctx->new_devobj, Irp, ctx->new_context); 
 
	} else 
		status = STATUS_SUCCESS; 
 
	/* patch IRP back */ 
 
	// restore routine and context 
	irps->CompletionRoutine = ctx->old_cr; 
	irps->Context = ctx->old_context; 
 
	// restore device object 
	irps->DeviceObject = DeviceObject; 
 
	Irp->CurrentLocation++; 
	Irp->Tail.Overlay.CurrentStackLocation++; 
 
	if (ctx->old_cr != NULL) { 
 
		if (status != STATUS_MORE_PROCESSING_REQUIRED) { 
			// call old completion (see the old control) 
			BOOLEAN b_call = FALSE; 
 
			if (Irp->Cancel) { 
				// cancel 
				if (ctx->old_control & SL_INVOKE_ON_CANCEL) 
					b_call = TRUE; 
			} else { 
				if (Irp->IoStatus.Status >= STATUS_SUCCESS) { 
					// success 
					if (ctx->old_control & SL_INVOKE_ON_SUCCESS) 
						b_call = TRUE; 
				} else { 
					// error 
					if (ctx->old_control & SL_INVOKE_ON_ERROR) 
						b_call = TRUE; 
				} 
			} 
 
			if (b_call) 
				status = ctx->old_cr(DeviceObject, Irp, ctx->old_context); 
		 
		} else { 
 
			/* 
			 * patch IRP to set IoManager to call completion next time 
			 */ 
 
			// restore Control 
			irps->Control = ctx->old_control; 
 
		} 
	} 
 
	free(ctx); 
 
	return status; 
} 
 
 
/* get original device object by filtered */ 
PDEVICE_OBJECT 
get_original_devobj(PDEVICE_OBJECT flt_devobj, int *proto) 
{ 
#ifndef USE_TDI_HOOKING 
	PDEVICE_OBJECT result; 
	int ipproto; 
 
	if (flt_devobj == g_tcpfltobj) { 
		result = g_tcpoldobj; 
		ipproto = IPPROTO_TCP; 
	} else if (flt_devobj == g_udpfltobj) { 
		result = g_udpoldobj; 
		ipproto = IPPROTO_UDP; 
	} else if (flt_devobj == g_ipfltobj) { 
		result = g_ipoldobj; 
		ipproto = IPPROTO_IP; 
	} else { 
		KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n", 
			flt_devobj)); 
		result = NULL; 
	} 
 
	if (result != NULL && proto != NULL) 
		*proto = ipproto; 
 
	return result; 
 
#else	/* USE_TDI_HOOKING */ 
 
	// just stub for original devobj; return proto by devobj 
	int ipproto; 
 
	if (flt_devobj == g_tcpfltobj) 
		ipproto = IPPROTO_TCP; 
	else if (flt_devobj == g_udpfltobj) 
		ipproto = IPPROTO_UDP; 
	else if (flt_devobj == g_ipfltobj) 
		ipproto = IPPROTO_IP; 
	else { 
		KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n", 
			flt_devobj)); 
		return NULL; 
	} 
 
	if (proto != NULL) 
		*proto = ipproto; 
 
	return flt_devobj; 
 
#endif 
} 
 
/* 
 * Completion routines must call this function at the end of their execution 
 */ 
NTSTATUS 
tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 
{ 
	KdPrint(("[tdi_fw] tdi_generic_complete: STATUS = 0x%x\n", Irp->IoStatus.Status)); 
 
	if (Irp->PendingReturned) { 
		KdPrint(("[tdi_fw] tdi_generic_complete: PENDING\n")); 
		IoMarkIrpPending(Irp); 
	} 
 
	return STATUS_SUCCESS; 
}