/*++ Module Name: device.c - Device handling events for example driver. Abstract: This file contains the device entry points and callbacks. Environment: Kernel-mode Driver Framework --*/ #include "precomp.h" #include "driver.h" #include "device.tmh" #ifdef ALLOC_PRAGMA #pragma alloc_text (PAGE, dnsfirewallCreateDevice) #endif NTSTATUS dnsfirewallCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - Pointer to an opaque init structure. Memory for this structure will be freed by the framework when the WdfDeviceCreate succeeds. So don't access the structure after that point. Return Value: NTSTATUS --*/ { NTSTATUS status; WDF_FILEOBJECT_CONFIG fileConfig; PAGED_CODE(); DECLARE_CONST_UNICODE_STRING(ntDeviceName, DNSFIREWALL_DEVICE_NAME); DECLARE_CONST_UNICODE_STRING(symbolicLinkName, DNSFIREWALL_SYMBOLIC_NAME); TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Enter" ); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); if (!NT_SUCCESS(status)) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! WdfDeviceInitAssignName failed %!STATUS!", status ); goto End; } WdfControlDeviceInitSetShutdownNotification( DeviceInit, dnsfirewallShutdown, WdfDeviceShutdown ); // // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the // framework whether you are interested in handling Create, Close and // Cleanup requests that gets generated when an application or another // kernel component opens an handle to the device. If you don't register // the framework default behaviour would be to complete these requests // with STATUS_SUCCESS. A driver might be interested in registering these // events if it wants to do security validation and also wants to maintain // per handle (fileobject) context. // WDF_FILEOBJECT_CONFIG_INIT( &fileConfig, dnsfirewallEvtDeviceFileCreate, dnsfirewallEvtFileClose, WDF_NO_EVENT_CALLBACK // not interested in Cleanup ); fileConfig.FileObjectClass = (WDF_FILEOBJECT_CLASS) (WdfFileObjectWdfCannotUseFsContexts | WdfFileObjectCanBeOptional); WdfDeviceInitSetFileObjectConfig( DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES ); status = WdfDeviceCreate( &DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &g_wdfControlDevice ); if (!NT_SUCCESS(status)) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! WdfDeviceCreate failed %!STATUS!", status ); goto End; } // // Create a symbolic link for the control object so that usermode can open // the device. // status = WdfDeviceCreateSymbolicLink( g_wdfControlDevice, &symbolicLinkName ); if (!NT_SUCCESS(status)) { // // Control device will be deleted automatically by the framework. // TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! WdfDeviceCreateSymbolicLink failed %!STATUS!", status ); goto End; } // // Initialize the I/O Package and any Queues // status = dnsfirewallQueueInitialize(g_wdfControlDevice); if (!NT_SUCCESS(status)) { // // Control g_wdfControlDevice will be deleted automatically by the framework. // TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! dnsfirewallQueueInitialize failed %!STATUS!", status ); goto End; } // // Control devices must notify WDF when they are done initializing. I/O is // rejected until this call is made. // WdfControlFinishInitializing(g_wdfControlDevice); End: ; // // If the device is created successfully, framework would clear the // DeviceInit value. Otherwise device create must have failed so we // should free the memory ourself. // if (DeviceInit != NULL) { WdfDeviceInitFree(DeviceInit); } TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit" ); return status; } VOID dnsfirewallShutdown( WDFDEVICE Device ) /*++ Routine Description: Callback invoked when the machine is shutting down. If you register for a last chance shutdown notification you cannot do the following: o Call any pageable routines o Access pageable memory o Perform any file I/O operations If you register for a normal shutdown notification, all of these are available to you. This function implementation does nothing, but if you had any outstanding file handles open, this is where you would close them. Arguments: Device - The device which registered the notification during init Return Value: None --*/ { Device; BOOLEAN bSignalWorkerThread; TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Enter" ); if (!g_bDriverUnload) { bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue); g_bDriverUnload = TRUE; if (bSignalWorkerThread) { KeSetEvent( &g_oWorkerEvent, 0, FALSE ); } } TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit" ); } VOID dnsfirewallEvtDeviceFileCreate( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject ) { NTSTATUS status = STATUS_SUCCESS; PUNICODE_STRING fileName; WDFDEVICE wdfDeviceObject = Device; WDF_OBJECT_ATTRIBUTES stFlowContextAttributes; PFLOW_DATA pFlowContext = NULL; USHORT length = 0; WDF_IO_QUEUE_CONFIG stFlowContextQueueConfig; int nFileIndex, nThreadIndex, nSubstrIndex; wchar_t *pEndPtr, *pSubstr, sCopy[32]; if (NULL == FileObject) { goto End; } // // Parsed filename has "\" in the begining. The object manager strips // of all "\", except one, after the device name. // fileName = WdfFileObjectGetFileName(FileObject); length = fileName->Length; if (length > 0) { pSubstr = wcschr( fileName->Buffer, L'@' ); #pragma warning(suppress: 28182) nFileIndex = wcstoul( &pSubstr[1], &pEndPtr, 10 ); nSubstrIndex = (int)(pSubstr - fileName->Buffer); #pragma warning(suppress: 28719) wcsncpy( sCopy, fileName->Buffer, nSubstrIndex ); sCopy[nSubstrIndex] = L'\0'; nThreadIndex = wcstoul( &sCopy[2], &pEndPtr, 10 ); } else { goto End; } WdfObjectAcquireLock(wdfDeviceObject); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&stFlowContextAttributes, FLOW_DATA); status = WdfObjectAllocateContext( FileObject, &stFlowContextAttributes, (PVOID*) &pFlowContext ); if (!NT_SUCCESS(status)) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! WdfObjectAllocateContext failed with status %!STATUS!", status ); WdfObjectReleaseLock(wdfDeviceObject); goto End; } pFlowContext->pThis = pFlowContext; pFlowContext->nFileIndex = nFileIndex; pFlowContext->nThreadIndex = nThreadIndex; pFlowContext->wdfFlowFileObject = FileObject; pFlowContext->enFlowDataOwner = foFreeFileList; push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner); InsertTailList( &g_stFreeFileList, &pFlowContext->listEntry ); WDF_IO_QUEUE_CONFIG_INIT( &stFlowContextQueueConfig, WdfIoQueueDispatchSequential ); stFlowContextQueueConfig.AllowZeroLengthRequests = TRUE; stFlowContextQueueConfig.EvtIoDeviceControl = flowControlEvtIoDeviceControl; status = WdfIoQueueCreate( Device, &stFlowContextQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pFlowContext->wdfFlowQueue ); if (!NT_SUCCESS(status)) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! WdfIoQueueCreate failed with status %!STATUS!", status ); WdfObjectReleaseLock(wdfDeviceObject); goto End; } WdfObjectReleaseLock(wdfDeviceObject); End: WdfRequestComplete(Request, status); } VOID dnsfirewallEvtFileClose( IN WDFFILEOBJECT wdfFlowFileObject ) { BOOLEAN bSignalWorkerThread; PLIST_ENTRY pFileListEntry, pLastLE, pNextLE; PFLOW_DATA pFlowData; PADDRESSES_DESCRIPTOR pDeviceAddressesDescriptor = NULL; NTSTATUS status = STATUS_SUCCESS; BOOLEAN bEmptyList, bFind, bEmpty; WDFQUEUE wdfRequestQueue = NULL; WDFREQUEST wdfPendedRequest = NULL; PNET_BUFFER_LIST pNetBufferList; TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Enter" ); WdfObjectAcquireLock(g_wdfControlDevice); if (NULL == wdfFlowFileObject) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! g_bDriverUnload = %!bool!", g_bDriverUnload ); if (!g_bDriverUnload) { bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue); g_bDriverUnload = TRUE; if (bSignalWorkerThread) { KeSetEvent( &g_oWorkerEvent, 0, FALSE ); } WdfObjectReleaseLock(g_wdfControlDevice); KeWaitForSingleObject( &g_oWorkerDoneEvent, Executive, KernelMode, FALSE, NULL ); WdfObjectAcquireLock(g_wdfControlDevice); } TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == wdfFlowFileObject)" ); WdfObjectReleaseLock(g_wdfControlDevice); return; } pFlowData = WdfObjectGetTypedContext( wdfFlowFileObject, FLOW_DATA ); if (NULL == pFlowData) { if ((!IsListEmpty(&g_stFlowedFileList)) || (!IsListEmpty(&g_stUdpALEFlowEstablishList)) || (!IsListEmpty(&g_stUdpALEAcceptPendedList)) || (!IsListEmpty(&g_stUdpAcceptNotifyList)) || (!IsListEmpty(&g_stUdpALEAcceptRecvList)) || (!IsListEmpty(&g_stUdpInboundList)) || (!IsListEmpty(&g_stAcceptableList)) || (!IsListEmpty(&g_stWaitForSetFilterFileList)) || (!IsListEmpty(&g_stWaitForQuery2FileList)) || (!IsListEmpty(&g_stWaitForDoneFileList))) { TraceEvents( TRACE_LEVEL_WARNING, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! DNSFIREWALL Filters files not Cleared" ); g_bFiltersChangeInProgress = TRUE; pDeviceAddressesDescriptor = WdfObjectGetTypedContext( g_wdfControlDevice, ADDRESSES_DESCRIPTOR ); if (NULL != pDeviceAddressesDescriptor) { FilterDataCleanup(pDeviceAddressesDescriptor); } else { ASSERT(FALSE); } } TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit (DNSFIREWALL Device was Closed)" ); WdfObjectReleaseLock(g_wdfControlDevice); return; } // NULL != pFlowData switch (pFlowData->enContextState) { case csFlowDeleted: case csNotRun: break; case csWaitQueryStarted: case csUdpWaitSetFilterStarted: case csUdpWaitQuery2Started: case csWaitFlowDoneStarted: ASSERT(pFlowData == pFlowData->pThis); wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; default: if (!IsListEmpty(&g_stUdpALEFlowEstablishList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stUdpALEFlowEstablishList.Blink; pNextLE = g_stUdpALEFlowEstablishList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { ASSERT(pFlowData == pFlowData->pThis); pFlowData->bUdpQueryClassifyPended = FALSE; pNetBufferList = pFlowData->pUdpQueryCloneBufferList; if (NULL != pNetBufferList) { pFlowData->pUdpQueryCloneBufferList = NULL; FwpsFreeCloneNetBufferList( pNetBufferList, 0 ); } pNetBufferList = pFlowData->pUdpQueryBufferList; if (NULL != pNetBufferList) { pFlowData->pUdpQueryBufferList = NULL; FwpsDereferenceNetBufferList( pNetBufferList, FALSE ); } if (csUdpPermitQueryPended == pFlowData->enContextState) { if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue)) { bEmpty = RemoveEntryList(&pFlowData->threadListEntry); } } wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; } } if (!IsListEmpty(&g_stUdpALEAcceptPendedList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stUdpALEAcceptPendedList.Blink; pNextLE = g_stUdpALEAcceptPendedList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { ASSERT(pFlowData == pFlowData->pThis); pFlowData->bUdpQueryClassifyPended = FALSE; pNetBufferList = pFlowData->pUdpQueryCloneBufferList; if (NULL != pNetBufferList) { pFlowData->pUdpQueryCloneBufferList = NULL; FwpsFreeCloneNetBufferList( pNetBufferList, 0 ); } pNetBufferList = pFlowData->pUdpQueryBufferList; if (NULL != pNetBufferList) { pFlowData->pUdpQueryBufferList = NULL; FwpsDereferenceNetBufferList( pNetBufferList, FALSE ); } if (csUdpPermitQueryPended == pFlowData->enContextState) { if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue)) { bEmpty = RemoveEntryList(&pFlowData->threadListEntry); } } wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; } } if (!IsListEmpty(&g_stUdpAcceptNotifyList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stUdpAcceptNotifyList.Blink; pNextLE = g_stUdpAcceptNotifyList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { ASSERT(pFlowData == pFlowData->pThis); wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; } } if (!IsListEmpty(&g_stUdpALEAcceptRecvList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stUdpALEAcceptRecvList.Blink; pNextLE = g_stUdpALEAcceptRecvList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { ASSERT(pFlowData == pFlowData->pThis); wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; } } if (!IsListEmpty(&g_stUdpInboundList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stUdpInboundList.Blink; pNextLE = g_stUdpInboundList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { ASSERT(pFlowData == pFlowData->pThis); pFlowData->bUdpQueryClassifyPended = FALSE; pNetBufferList = pFlowData->pUdpQuery2BufferList; if (NULL != pNetBufferList) { pFlowData->pUdpQuery2BufferList = NULL; FwpsDereferenceNetBufferList( pNetBufferList, FALSE ); } wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitDnsQueryQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitUdpQuery2Queue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue; if (NULL != wdfRequestQueue) { pFlowData->wdfWaitFlowDoneQueue = NULL; status = WdfIoQueueRetrieveNextRequest( wdfRequestQueue, &wdfPendedRequest ); if (NT_SUCCESS(status)) { WdfRequestCompleteWithInformation( wdfPendedRequest, STATUS_END_OF_FILE, 0 ); } else if (STATUS_NO_MORE_ENTRIES != status) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!", status ); } WdfObjectDelete(wdfRequestQueue); } bEmptyList = RemoveEntryList(&pFlowData->listEntry); pFlowData->enContextState = csNotRun; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); break; } } pFlowData->enContextState = csFlowDeleted; push_css(pFlowData->arContextStateStack, pFlowData->enContextState); if (!IsListEmpty(&g_stFlowedFileList)) { pFileListEntry = &pFlowData->listEntry; pLastLE = g_stFlowedFileList.Blink; pNextLE = g_stFlowedFileList.Flink; bFind = FALSE; for (;;) { if (pNextLE == pFileListEntry) { bFind = TRUE; break; } if (pNextLE == pLastLE) { break; } pNextLE = pNextLE->Flink; } if (bFind) { WdfObjectReleaseLock(g_wdfControlDevice); if (IPPROTO_UDP == pFlowData->enIpProto) { if (pFlowData->bIPv6) { status = FwpsFlowRemoveContext( pFlowData->flowHandle, FWPS_LAYER_DATAGRAM_DATA_V6, g_nDatagramIdV6 ); } else { status = FwpsFlowRemoveContext( pFlowData->flowHandle, FWPS_LAYER_DATAGRAM_DATA_V4, g_nDatagramIdV4 ); } } else { if (pFlowData->bIPv6) { status = FwpsFlowRemoveContext( pFlowData->flowHandle, FWPS_LAYER_STREAM_V6, g_nStreamIdV6 ); } else { status = FwpsFlowRemoveContext( pFlowData->flowHandle, FWPS_LAYER_STREAM_V4, g_nStreamIdV4 ); } } if (!NT_SUCCESS(status)) { TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!", status ); } TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit (Remove Flow context)" ); return; } // !bFind TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! DNSFIREWALL Wrong g_stFlowedFileList; nFileIndex = %d; nThreadIndex = %d; enContextState = %u;", pFlowData->nFileIndex, pFlowData->nThreadIndex, pFlowData->arContextStateStack[1] ); break; } // IsListEmpty(&g_stFlowedFileList) TraceEvents( TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! DNSFIREWALL g_stFlowedFileList is Empty; nFileIndex = %d; nThreadIndex = %d; enContextState = %u;", pFlowData->nFileIndex, pFlowData->nThreadIndex, pFlowData->arContextStateStack[1] ); break; } TraceEvents( TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! line:%!LINE! %!LEVEL! Exit" ); WdfObjectReleaseLock(g_wdfControlDevice); }