www.pudn.com > tdi_fw.zip > obj_tbl.c
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs) // // $Id: obj_tbl.c,v 1.3 2002/12/03 12:14:27 dev Exp $ /* * Working with connection objects, address objects and links between them */ #include#include #include "sock.h" #include "memtrack.h" #include "obj_tbl.h" #include "tdi_fw.h" #define HASH_SIZE 0x1000 #define CALC_HASH(fileobj) (((ULONG)(fileobj) >> 5) % HASH_SIZE) static struct ot_entry **g_ot_hash; KSPIN_LOCK g_ot_hash_guard; struct ctx_entry { struct ctx_entry *next; PFILE_OBJECT addrobj; CONNECTION_CONTEXT conn_ctx; PFILE_OBJECT connobj; }; static struct ctx_entry **g_cte_hash; KSPIN_LOCK g_cte_hash_guard; static NTSTATUS do_set_old_event_handler(struct ot_entry *ote, int event_type); //---------------------------------------------------------------------------- NTSTATUS ot_init(void) { g_ot_hash = (struct ot_entry **)malloc_np(sizeof(*g_ot_hash) * HASH_SIZE); if (g_ot_hash == NULL) { KdPrint(("[tdi_fw] ot_init: malloc_np\n")); return STATUS_INSUFFICIENT_RESOURCES; } memset(g_ot_hash, 0, sizeof(*g_ot_hash) * HASH_SIZE); KeInitializeSpinLock(&g_ot_hash_guard); g_cte_hash = (struct ctx_entry **)malloc_np(sizeof(*g_cte_hash) * HASH_SIZE); if (g_cte_hash == NULL) { KdPrint(("[tdi_fw] ot_init: malloc_np\n")); free(g_ot_hash); return STATUS_INSUFFICIENT_RESOURCES; } memset(g_cte_hash, 0, sizeof(*g_cte_hash) * HASH_SIZE); KeInitializeSpinLock(&g_cte_hash_guard); return STATUS_SUCCESS; } void ot_free(void) { KIRQL irql; int i; if (g_ot_hash != NULL) { KeAcquireSpinLock(&g_ot_hash_guard, &irql); for (i = 0; i < HASH_SIZE; i++) { struct ot_entry *ote = g_ot_hash[i]; while (ote) { struct ot_entry *ote2 = ote->next; int j; KdPrint(("[tdi_fw] ot_free: Warning! fileobj 0x%x type %d exists!\n", ote->fileobj, ote->type)); if (ote->signature != 'OTE ') { KdPrint(("[tdi_fw] ot_free: Warning! fileobj 0x%x invalid signature 0x%x!\n", ote->fileobj, ote->signature)); } for (j = 0; j < MAX_EVENT; j++) if (ote->ctx[j].old_handler != NULL) do_set_old_event_handler(ote, j); free(ote); ote = ote2; } } free(g_ot_hash); g_ot_hash = NULL; KeReleaseSpinLock(&g_ot_hash_guard, irql); } if (g_cte_hash != NULL) { KeAcquireSpinLock(&g_cte_hash_guard, &irql); for (i = 0; i < HASH_SIZE; i++) { struct ctx_entry *cte = g_cte_hash[i]; while (cte) { struct ctx_entry *cte2 = cte->next; free(cte); cte = cte2; } } free(g_cte_hash); g_cte_hash = NULL; KeReleaseSpinLock(&g_cte_hash_guard, irql); } } //---------------------------------------------------------------------------- NTSTATUS ot_add_fileobj(PDEVICE_OBJECT devobj, PFILE_OBJECT fileobj, int fileobj_type, CONNECTION_CONTEXT conn_ctx, int no_guard) { ULONG hash = CALC_HASH(fileobj); KIRQL irql; struct ot_entry *ote; NTSTATUS status; int i; if (fileobj == NULL) return STATUS_INVALID_PARAMETER_2; if (!no_guard) KeAcquireSpinLock(&g_ot_hash_guard, &irql); for (ote = g_ot_hash[hash]; ote != NULL; ote = ote->next) if (ote->fileobj == fileobj) break; if (ote == NULL) { ote = (struct ot_entry *)malloc_np(sizeof(*ote)); if (ote == NULL) { KdPrint(("[tdi_fw] ot_add_fileobj: malloc_np\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto done; } memset(ote, 0, sizeof(*ote)); ote->next = g_ot_hash[hash]; g_ot_hash[hash] = ote; ote->fileobj = fileobj; for (i = 0; i < MAX_EVENT; i++) ote->ctx[i].fileobj = fileobj; } else { KdPrint(("[tdi_fw] ot_add_fileobj: reuse fileobj 0x%x\n", fileobj)); // set neccessary fields to zero ote->associated_fileobj = NULL; memset(ote->ctx, 0, sizeof(ote->ctx)); memset(ote->local_addr, 0, sizeof(ote->local_addr)); memset(ote->remote_addr, 0, sizeof(ote->remote_addr)); } ote->signature = 'OTE '; ote->pid = (ULONG)PsGetCurrentProcessId(); ote->devobj = devobj; ote->type = fileobj_type; ote->conn_ctx = conn_ctx; status = STATUS_SUCCESS; done: if (!no_guard) KeReleaseSpinLock(&g_ot_hash_guard, irql); return status; } NTSTATUS ot_del_fileobj(PFILE_OBJECT fileobj, int *fileobj_type) { ULONG hash = CALC_HASH(fileobj); KIRQL irql; struct ot_entry *ote, *prev_ote; NTSTATUS status; if (fileobj == NULL) return STATUS_INVALID_PARAMETER_1; KeAcquireSpinLock(&g_ot_hash_guard, &irql); prev_ote = NULL; for (ote = g_ot_hash[hash]; ote; ote = ote->next) { if (ote->fileobj == fileobj) break; prev_ote = ote; } if (ote == NULL) { KdPrint(("[tdi_fw] ot_del_fileobj: fileobj 0x%x not found!\n", fileobj)); status = STATUS_OBJECT_NAME_NOT_FOUND; goto done; } if (fileobj_type != NULL) *fileobj_type = ote->type; if (prev_ote != NULL) prev_ote->next = ote->next; else g_ot_hash[hash] = ote->next; free(ote); status = STATUS_SUCCESS; done: KeReleaseSpinLock(&g_ot_hash_guard, irql); return status; } struct ot_entry * ot_find_fileobj(PFILE_OBJECT fileobj, KIRQL *irql) { ULONG hash = CALC_HASH(fileobj); struct ot_entry *ote; if (fileobj == NULL) return NULL; if (irql != NULL) KeAcquireSpinLock(&g_ot_hash_guard, irql); for (ote = g_ot_hash[hash]; ote != NULL; ote = ote->next) if (ote->fileobj == fileobj) break; if (ote == NULL) { KdPrint(("[tdi_fw] ot_find_fileobj: fileobj 0x%x not found!\n", fileobj)); if (irql != NULL) KeReleaseSpinLock(&g_ot_hash_guard, *irql); } return ote; } //---------------------------------------------------------------------------- #define CALC_HASH_2(addrobj, conn_ctx) CALC_HASH((ULONG)(addrobj) ^ (ULONG)(conn_ctx)) NTSTATUS ot_add_conn_ctx(PFILE_OBJECT addrobj, CONNECTION_CONTEXT conn_ctx, PFILE_OBJECT connobj) { ULONG hash = CALC_HASH_2(addrobj, conn_ctx); KIRQL irql; struct ctx_entry *cte; NTSTATUS status; KeAcquireSpinLock(&g_cte_hash_guard, &irql); for (cte = g_cte_hash[hash]; cte != NULL; cte = cte->next) if (cte->addrobj == addrobj && cte->conn_ctx == conn_ctx) break; if (cte == NULL) { KdPrint(("[tdi_fw] ot_add_fileobj: reuse addrobj 0x%x, conn_ctx 0x%x\n", addrobj, conn_ctx)); cte = (struct ctx_entry *)malloc_np(sizeof(*cte)); if (cte == NULL) { KdPrint(("[tdi_fw] ot_add_conn_ctx: malloc_np\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto done; } cte->next = g_cte_hash[hash]; g_cte_hash[hash] = cte; cte->addrobj = addrobj; cte->conn_ctx = conn_ctx; } cte->connobj = connobj; status = STATUS_SUCCESS; done: KeReleaseSpinLock(&g_cte_hash_guard, irql); return status; } NTSTATUS ot_del_conn_ctx(PFILE_OBJECT addrobj, CONNECTION_CONTEXT conn_ctx) { ULONG hash = CALC_HASH_2(addrobj, conn_ctx); KIRQL irql; struct ctx_entry *cte, *prev_cte; NTSTATUS status; KeAcquireSpinLock(&g_cte_hash_guard, &irql); prev_cte = NULL; for (cte = g_cte_hash[hash]; cte != NULL; cte = cte->next) { if (cte->addrobj == addrobj && cte->conn_ctx == conn_ctx) break; prev_cte = cte; } if (cte == NULL) { KdPrint(("[tdi_fw] ot_del_conn_ctx: addrobj 0x%x not found!\n", addrobj)); status = STATUS_OBJECT_NAME_NOT_FOUND; goto done; } if (prev_cte != NULL) prev_cte->next = cte->next; else g_cte_hash[hash] = cte->next; free(cte); status = STATUS_SUCCESS; done: KeReleaseSpinLock(&g_cte_hash_guard, irql); return status; } PFILE_OBJECT ot_find_conn_ctx(PFILE_OBJECT addrobj, CONNECTION_CONTEXT conn_ctx) { ULONG hash = CALC_HASH_2(addrobj, conn_ctx); KIRQL irql; struct ctx_entry *cte; PFILE_OBJECT result = NULL; KeAcquireSpinLock(&g_cte_hash_guard, &irql); for (cte = g_cte_hash[hash]; cte != NULL; cte = cte->next) if (cte->addrobj == addrobj && cte->conn_ctx == conn_ctx) { result = cte->connobj; break; } KeReleaseSpinLock(&g_cte_hash_guard, irql); return result; } //---------------------------------------------------------------------------- NTSTATUS do_set_old_event_handler(struct ot_entry *ote, int event_type) { NTSTATUS status; PIRP query_irp = NULL; PDEVICE_OBJECT devobj; #ifndef USE_TDI_HOOKING // get original (unhooked) device object if (ote->devobj == g_tcpfltobj) devobj = g_tcpoldobj; else if (ote->devobj == g_udpfltobj) devobj = g_udpoldobj; else if (ote->devobj == g_ipfltobj) devobj = g_ipoldobj; else return STATUS_UNSUCCESSFUL; #else // original and hooked device objects are the same devobj = ote->devobj; #endif KdPrint(("[tdi_fw] do_set_old_event_handler: devobj 0x%x, fileobj 0x%x, handler 0x%x, context 0x%x\n", devobj, ote->fileobj, ote->ctx[event_type].old_handler, ote->ctx[event_type].old_context)); // FIXME!!! Calling TdiBuildInternalDeviceControlIrp at DISPATCH_LEVEL!!! query_irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devobj, ote->fileobj, NULL, NULL); if (query_irp == NULL) { KdPrint(("[tdi_fw] do_set_old_event_handler: TdiBuildInternalDeviceControlIrp\n")); status = STATUS_UNSUCCESSFUL; goto done; } TdiBuildSetEventHandler(query_irp, devobj, ote->fileobj, NULL, NULL, event_type, ote->ctx[event_type].old_handler, ote->ctx[event_type].old_context); status = IoCallDriver(devobj, query_irp); query_irp = NULL; if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] do_set_old_event_handler: IoCallDriver: 0x%x\n", status)); goto done; } // don't wait to complete done: if (query_irp) IoFreeIrp(query_irp); return status; }