
#include "precomp.h"
#include "driver.h"
#include "dnsfirewall.tmh"


BOOLEAN IsListEntryInList(
    PLIST_ENTRY pListEntry,
    PLIST_ENTRY pListHead
    )
{
    PLIST_ENTRY pCurrentLE, pLastLE;
    if (IsListEmpty(pListHead))
    {
        return FALSE;
    }
    pCurrentLE = pListHead->Flink;
    pLastLE = pListHead->Blink;
    for (;;)
    {
        if (pCurrentLE == pListEntry)
        {
            return TRUE;
        }
        pCurrentLE = pCurrentLE->Flink;
        if (pCurrentLE == pLastLE)
        {
            break;
        }
    }
    return FALSE;
}


NTSTATUS dnsfirewallCoInitialize(PDEVICE_OBJECT deviceObject)
{
    NTSTATUS    status = STATUS_SUCCESS;
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! Enter"
        );
    InitializeListHead(&g_stFreeFileList);
    InitializeListHead(&g_stWaitForDoneFileList);
    InitializeListHead(&g_stWaitForQuery2FileList);
    InitializeListHead(&g_stWaitForSetFilterFileList);
    InitializeListHead(&g_stAcceptableList);
    InitializeListHead(&g_stUdpInboundList);
    InitializeListHead(&g_stUdpAcceptNotifyList);
    InitializeListHead(&g_stUdpALEAcceptRecvList);
    InitializeListHead(&g_stUdpALEAcceptPendedList);
    InitializeListHead(&g_stUdpALEFlowEstablishList);
    InitializeListHead(&g_stFlowedFileList);
    InitializeListHead(&g_stPendedPacketsQueue);
    KeInitializeEvent(
        &g_oWorkerEvent,
        NotificationEvent,
        FALSE
        );
    KeInitializeEvent(
        &g_oWorkerDoneEvent,
        NotificationEvent,
        FALSE
        );
    status = FwpsInjectionHandleCreate(
        AF_INET,
        FWPS_INJECTION_TYPE_STREAM | FWPS_INJECTION_TYPE_TRANSPORT | FWPS_INJECTION_TYPE_NETWORK,
        &g_hInjectionHandleV4
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsInjectionHandleCreate for AF_INET failed with status %!STATUS!",
            status
            );
        return status;
    }
    status = FwpsInjectionHandleCreate(
        AF_INET6,
        FWPS_INJECTION_TYPE_STREAM | FWPS_INJECTION_TYPE_TRANSPORT | FWPS_INJECTION_TYPE_NETWORK,
        &g_hInjectionHandleV6
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsInjectionHandleCreate for AF_INET6 failed with status %!STATUS!",
            status
            );
        return status;
    }
    status = dnsfirewallCoRegisterCallouts(deviceObject);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! dnsfirewallCoRegisterCallouts failed with status %!STATUS!",
            status
            );
        return status;
    }
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! Exit"
        );
    return status;
}

NTSTATUS
dnsfirewallCoRegisterCallouts(
PDEVICE_OBJECT deviceObject
)
{
    NTSTATUS        status = STATUS_SUCCESS;
    FWPS_CALLOUT    stCallout;
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! Enter"
        );
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DNS_FIREWALL_INBOUND_TRANSPORT_CALLOUT_V4;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onInboundTransportV4Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nInboundTransportV4Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DNS_FIREWALL_INBOUND_TRANSPORT_CALLOUT_V6;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onInboundTransportV6Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nInboundTransportV6Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    stCallout.calloutKey = DNS_FIREWALL_ALE_ACCEPT_RECV_CALLOUT_V4;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onAleAcceptRecvV4Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nAleAcceptRecvV4Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DNS_FIREWALL_ALE_ACCEPT_RECV_CALLOUT_V6;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onAleAcceptRecvV6Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nAleAcceptRecvV6Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    //
    // We won't be called for flow deletion for the flow established layer 
    // since we only establish a flow for the stream layer, so we don't
    // specify a flow deletion function.
    //
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DNS_FIREWALL_ALE_FLOW_ESTABLISHED_CALLOUT_V4;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onAleFlowEstablishedV4Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nAleFlowEstablishedV4Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DNS_FIREWALL_ALE_FLOW_ESTABLISHED_CALLOUT_V6;
    //stCallout.flags = FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY;
    stCallout.classifyFn = onAleFlowEstablishedV6Classify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = (FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN) NULL; // We don't need a flow delete function at this layer.
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nAleFlowEstablishedV6Id
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DSN_FIREWALL_STREAM_CALLOUT_V4;
    stCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; // FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY | 
    stCallout.classifyFn = onStreamClassify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = onDnsFlowDeletion;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nStreamIdV4
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DSN_FIREWALL_STREAM_CALLOUT_V6;
    stCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; // FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY | 
    stCallout.classifyFn = onStreamClassify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = onDnsFlowDeletion;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nStreamIdV6
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DSN_FIREWALL_DATAGRAM_DATA_CALLOUT_V4;
    stCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; // FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY | 
    stCallout.classifyFn = onDatagramDataClassify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = onDnsFlowDeletion;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nDatagramIdV4
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    RtlZeroMemory(
        &stCallout,
        sizeof(stCallout)
        );
    stCallout.calloutKey = DSN_FIREWALL_DATAGRAM_DATA_CALLOUT_V6;
    stCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; // FWP_CALLOUT_FLAG_ENABLE_COMMIT_ADD_NOTIFY | 
    stCallout.classifyFn = onDatagramDataClassify;
    stCallout.notifyFn = onFiltersChangeNotify;
    stCallout.flowDeleteFn = onDnsFlowDeletion;
    status = FwpsCalloutRegister(
        deviceObject,
        &stCallout,
        &g_nDatagramIdV6
        );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! FwpsCalloutRegister failed with status %!STATUS!",
            status
            );
        return status;
    }
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! Exit"
        );
    return status;
}

void NTAPI onAleFlowEstablishedV4Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    PADDRESSES_DESCRIPTOR   pAddressesDescriptor = NULL;
    UINT32                  ulRemoteAddress, ulI, ulRemoteAddressN;
    int                     i;
    BOOLEAN                 bLocalNetwork = FALSE;
    PLIST_ENTRY             pListEntry, pFirstLE;
    PFLOW_DATA              pFlowContext = NULL, pFirstEstablishingFlowContext = NULL;
    WDFFILEOBJECT           wdfFlowFileObject = NULL;
    IPPROTO                 enIpProto;
    UINT64                  flowHandle = 0, uiOldFlowHandle;
    NTSTATUS                status = STATUS_SUCCESS;
    BOOLEAN                 bEmpty;
    UINT32                  ulInboundCount = 0;
    UINT16                  usRemotePort;
    IN_ADDR                 stIpAddress;
    WCHAR                   szIpAddress[128];
    LPWSTR                  pAddressEnd;
    BOOLEAN                 bTestIpV4;
    WDFREQUEST              wdfPendedRequest;
    WDFMEMORY               wdfOutputMemory;
    UNREFERENCED_PARAMETER(layerData);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    ASSERT(FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 == inFixedValues->layerId);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    ulRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32;
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_FLOW_HANDLE)
        );
    flowHandle = inMetaValues->flowHandle;
    ASSERT(0 != flowHandle);
    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
    bTestIpV4 = ((IPPROTO_UDP == enIpProto) && (c_ulTestIpV4 == ulRemoteAddress));
    if (bTestIpV4)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
    }
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor->m_pDataArray)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (c_ulLocalHost == ulRemoteAddress)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPublicIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPrivateIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPublicRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPublicRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IPPROTO_UDP == enIpProto)
    {
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if ((IPPROTO_UDP == pFlowContext->enIpProto) && (!pFlowContext->bIPv6))
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (usRemotePort == pFlowContext->usRemotePort)
                        && pFlowContext->bUdpQueryClassifyPended)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitPermitQuery2:
                        case csUdpPermitQuery2Done:
                            pFirstEstablishingFlowContext = pFlowContext;
                            ulInboundCount++;
                            break;
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pListEntry->Blink;
            }
            if (ulInboundCount > 0)
            {
                ASSERT(1 == ulInboundCount);
                pFlowContext = pFirstEstablishingFlowContext;
                pFlowContext->bUdpQueryClassifyPended = FALSE;
                uiOldFlowHandle = pFlowContext->flowHandle;
                classifyOut->actionType = FWP_ACTION_PERMIT;
                if (uiOldFlowHandle != flowHandle)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Old Context for IpV4 Host %ws will Removed; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                    pFlowContext->flowHandle = flowHandle;
                    status = FwpsFlowAssociateContext(
                        flowHandle,
                        FWPS_LAYER_DATAGRAM_DATA_V4,
                        g_nDatagramIdV4,
                        (UINT64) pFlowContext
                        );
                    ASSERT(NT_SUCCESS(status));
                    pFlowContext->bUdpQuery2Reestablish = TRUE;
                    //if (bTestIpV4)
                    //{
                    //    TraceEvents(
                    //        TRACE_LEVEL_INFORMATION,
                    //        TRACE_DNSFIREWALL,
                    //        "%!FUNC! line:%!LINE! %!LEVEL! DNS Query from Tested IpV4 Host was Reestablished."
                    //        );
                    //}
                    WdfObjectReleaseLock(g_wdfControlDevice);
                    status = FwpsFlowRemoveContext(
                        uiOldFlowHandle,
                        FWPS_LAYER_DATAGRAM_DATA_V4,
                        g_nDatagramIdV4
                        );
                    if (!NT_SUCCESS(status))
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                            status
                            );
                    }
                    return;
                }
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
        }
        if (IsListEmpty(&g_stUdpALEFlowEstablishList))
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stUdpALEFlowEstablishList\" is Empty!! Host IP = %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = g_stUdpALEFlowEstablishList.Blink;
        pFirstLE = g_stUdpALEFlowEstablishList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    pFirstEstablishingFlowContext = pFlowContext;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (0 == ulInboundCount)
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Matched element in \"g_stUdpALEFlowEstablishList\" not Found!!"
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pFlowContext = pFirstEstablishingFlowContext;
        switch (pFlowContext->enContextState)
        {
        case csUdpAcceptedRecv:
            break;
        case csUdpWaitPermitQuery:
        case csUdpPermitQueryDone:
            if (!pFlowContext->bUdpQueryClassifyPended)
            {
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            break;
        default:
            ASSERT(FALSE);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
        if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
        {
            pFlowContext->bUdpNotifyQuery = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        for (ulI = 0; ulI < g_stFirewallConfig.nBlackSubnetListLength; ulI++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpMask);
            if (ulAddrPart == g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpAddr)
            {
                pFlowContext->bUdpNotifyQuery = FALSE;
                pFlowContext->enContextState = csWaitQueryStarted;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foAcceptableList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stAcceptableList,
                    &pFlowContext->listEntry
                    );
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
        }
        for (ulI = 0; ulI < g_stFirewallConfig.nBlackListLength; ulI++)
        {
            if (ulRemoteAddress == g_stFirewallConfig.aBlackListArray[ulI])
            {
                pFlowContext->bUdpNotifyQuery = FALSE;
                pFlowContext->enContextState = csWaitQueryStarted;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foAcceptableList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stAcceptableList,
                    &pFlowContext->listEntry
                    );
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
        }
        if (pFlowContext->bUdpNotifyQuery)
        {
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! NOTIFY Query will remove from UDP-flow."
                    );
            }
            pFlowContext->bUdpNotifyQuery = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pFlowContext->flowHandle = flowHandle;
        status = FwpsFlowAssociateContext(
            flowHandle,
            FWPS_LAYER_DATAGRAM_DATA_V4,
            g_nDatagramIdV4,
            (UINT64) pFlowContext
            );
        ASSERT(NT_SUCCESS(status));
        if (!pFlowContext->bUdpQueryClassifyPended)
        {
            pFlowContext->enContextState = csUdpFlowEstablished;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Pended Classify Packet was Injected for Host Ip = %ws; clent.port = %hu;",
                szIpAddress,
                pFlowContext->usRemotePort
                );
            //ASSERT(FALSE);
        }
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stFlowedFileList\"."
                );
        }
        pFlowContext->enFlowDataOwner = foFlowedFileList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stFlowedFileList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IsListEmpty(&g_stAcceptableList))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!!"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        if (NULL != g_wdfWaitRestartQueue)
        {
            status = WdfIoQueueRetrieveNextRequest(
                g_wdfWaitRestartQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                &g_uiRestartStatus,
                sizeof(g_uiRestartStatus)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(g_uiRestartStatus)
                );
            WdfObjectDelete(g_wdfWaitRestartQueue);
            g_wdfWaitRestartQueue = NULL;
        }
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pListEntry = RemoveHeadList(&g_stAcceptableList);
    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
    ASSERT(pFlowContext == pFlowContext->pThis);
    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
    pFlowContext->enIpProto = enIpProto;
    pFlowContext->nRemoteAddressV4 = ulRemoteAddress;
    pFlowContext->nRemoteAddressV4N = RtlUlongByteSwap(ulRemoteAddress);
    pFlowContext->usRemotePort = usRemotePort;
    pFlowContext->flowHandle = flowHandle;
    ASSERT(csWaitQueryStarted == pFlowContext->enContextState);
    status = FwpsFlowAssociateContext(
        flowHandle,
        FWPS_LAYER_STREAM_V4,
        g_nStreamIdV4,
        (UINT64) pFlowContext
        );
    pFlowContext->enContextState = csTcpFlowEstablished;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    ASSERT(NT_SUCCESS(status));
    if (bTestIpV4)
    {
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stFlowedFileList\"."
            );
    }
    pFlowContext->enFlowDataOwner = foFlowedFileList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stFlowedFileList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_PERMIT;
    WdfObjectReleaseLock(g_wdfControlDevice);
}

void NTAPI onAleFlowEstablishedV6Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    int i;
    PADDRESSES_DESCRIPTOR   pAddressesDescriptor = NULL;
    FWP_BYTE_ARRAY16        *pRemoteAddress;
    BOOLEAN                 bLocalNetwork = FALSE;
    PLIST_ENTRY             pListEntry, pFirstLE;
    PFLOW_DATA              pFlowContext = NULL, pFirstEstablishingFlowContext = NULL;
    WDFFILEOBJECT           wdfFlowFileObject = NULL;
    NTSTATUS                status = STATUS_SUCCESS;
    IPPROTO                 enIpProto;
    UINT64                  flowHandle = 0, uiOldFlowHandle;
    UINT32                  ulI, ulInboundCount = 0;
    UINT16                  usRemotePort;
    BOOLEAN                 bEmpty;
    IN6_ADDR                stIp6Address;
    WCHAR                   szIpAddress[128];
    LPWSTR                  pAddressEnd;
    WDFREQUEST              wdfPendedRequest;
    WDFMEMORY               wdfOutputMemory;
    UNREFERENCED_PARAMETER(layerData);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    ASSERT(FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6 == inFixedValues->layerId);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    pRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS].value.byteArray16;
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT].value.uint16;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_FLOW_HANDLE)
        );
    flowHandle = inMetaValues->flowHandle;
    ASSERT(0 != flowHandle);
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor->m_pDataArray)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!bfIPv6AddressInIPv6Subnet(pRemoteAddress, c_pGlobalIPv6Subnet))
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPublicIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPrivateIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IPPROTO_UDP == enIpProto)
    {
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if ((IPPROTO_UDP == pFlowContext->enIpProto) && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                        && (usRemotePort == pFlowContext->usRemotePort)
                        && pFlowContext->bUdpQueryClassifyPended)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitPermitQuery2:
                        case csUdpPermitQuery2Done:
                            pFirstEstablishingFlowContext = pFlowContext;
                            ulInboundCount++;
                            break;
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pListEntry->Blink;
            }
            if (ulInboundCount > 0)
            {
                ASSERT(1 == ulInboundCount);
                pFlowContext = pFirstEstablishingFlowContext;
                pFlowContext->bUdpQueryClassifyPended = FALSE;
                uiOldFlowHandle = pFlowContext->flowHandle;
                classifyOut->actionType = FWP_ACTION_PERMIT;
                if (uiOldFlowHandle != flowHandle)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        pRemoteAddress,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToStringW(
                        &stIp6Address,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Old Context for Host IP = %ws will Removed; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                    pFlowContext->flowHandle = flowHandle;
                    status = FwpsFlowAssociateContext(
                        flowHandle,
                        FWPS_LAYER_DATAGRAM_DATA_V6,
                        g_nDatagramIdV6,
                        (UINT64) pFlowContext
                        );
                    ASSERT(NT_SUCCESS(status));
                    pFlowContext->bUdpQuery2Reestablish = TRUE;
                    WdfObjectReleaseLock(g_wdfControlDevice);
                    status = FwpsFlowRemoveContext(
                        uiOldFlowHandle,
                        FWPS_LAYER_DATAGRAM_DATA_V6,
                        g_nDatagramIdV6
                        );
                    if (!NT_SUCCESS(status))
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                            status
                            );
                    }
                    return;
                }
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
        }
        if (IsListEmpty(&g_stUdpALEFlowEstablishList))
        {
            RtlCopyMemory(
                &stIp6Address,
                pRemoteAddress,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stUdpALEFlowEstablishList\" is Empty!! Host IP = %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = g_stUdpALEFlowEstablishList.Blink;
        pFirstLE = g_stUdpALEFlowEstablishList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    pFirstEstablishingFlowContext = pFlowContext;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (0 == ulInboundCount)
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Matched element in \"g_stUdpALEFlowEstablishList\" not Found!!"
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pFlowContext = pFirstEstablishingFlowContext;
        switch (pFlowContext->enContextState)
        {
        case csUdpAcceptedRecv:
            break;
        case csUdpWaitPermitQuery:
        case csUdpPermitQueryDone:
            if (!pFlowContext->bUdpQueryClassifyPended)
            {
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            break;
        default:
            ASSERT(FALSE);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
        if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
        {
            pFlowContext->bIPv6 = FALSE;
            pFlowContext->bUdpNotifyQuery = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        for (ulI = 0; ulI < g_stFirewallConfig.nBlackListV6Length; ulI++)
        {
            if (bfIsIPv6AddressesEqual(pRemoteAddress, &g_stFirewallConfig.aBlackListV6Array[ulI]))
            {
                pFlowContext->bIPv6 = FALSE;
                pFlowContext->bUdpNotifyQuery = FALSE;
                pFlowContext->enContextState = csWaitQueryStarted;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foAcceptableList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stAcceptableList,
                    &pFlowContext->listEntry
                    );
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
        }
        if (pFlowContext->bUdpNotifyQuery)
        {
            pFlowContext->bIPv6 = FALSE;
            pFlowContext->bUdpNotifyQuery = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pFlowContext->flowHandle = flowHandle;
        status = FwpsFlowAssociateContext(
            flowHandle,
            FWPS_LAYER_DATAGRAM_DATA_V6,
            g_nDatagramIdV6,
            (UINT64) pFlowContext
            );
        ASSERT(NT_SUCCESS(status));
        if (pFlowContext->bUdpQueryClassifyPended)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowContext->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Pended Classify Packet was Injected for Host Ip = %ws; clent.port = %hu;",
                szIpAddress,
                pFlowContext->usRemotePort
                );
        }
        else
        {
            pFlowContext->enContextState = csUdpFlowEstablished;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        }
        pFlowContext->enFlowDataOwner = foFlowedFileList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stFlowedFileList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IsListEmpty(&g_stAcceptableList))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!!"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        if (NULL != g_wdfWaitRestartQueue)
        {
            status = WdfIoQueueRetrieveNextRequest(
                g_wdfWaitRestartQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                &g_uiRestartStatus,
                sizeof(g_uiRestartStatus)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(g_uiRestartStatus)
                );
            WdfObjectDelete(g_wdfWaitRestartQueue);
            g_wdfWaitRestartQueue = NULL;
        }
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pListEntry = RemoveHeadList(&g_stAcceptableList);
    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
    ASSERT(pFlowContext == pFlowContext->pThis);
    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
    pFlowContext->bIPv6 = TRUE;
    pFlowContext->enIpProto = enIpProto;
    IPv6CopyAddress(&pFlowContext->stRemoteAddressV6, pRemoteAddress);
    pFlowContext->usRemotePort = usRemotePort;
    pFlowContext->flowHandle = flowHandle;
    ASSERT(csWaitQueryStarted == pFlowContext->enContextState);
    status = FwpsFlowAssociateContext(
        flowHandle,
        FWPS_LAYER_STREAM_V6,
        g_nStreamIdV6,
        (UINT64) pFlowContext
        );
    pFlowContext->enContextState = csTcpFlowEstablished;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    ASSERT(NT_SUCCESS(status));
    pFlowContext->enFlowDataOwner = foFlowedFileList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stFlowedFileList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_PERMIT;
    WdfObjectReleaseLock(g_wdfControlDevice);
}

NTSTATUS
onFiltersChangeNotify(
   _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
   _In_ const GUID* filterKey,
   _Inout_ const FWPS_FILTER* filter
    )
{
    NTSTATUS    status = STATUS_SUCCESS;
    if (FWPS_CALLOUT_NOTIFY_ADD_FILTER == notifyType)
    {
        if (NULL != filterKey)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Add WFP Filter with filterKey = %!GUID!",
                filterKey
                );
        }
        else
        {
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Add WFP Filter with filterKey = NULL"
                );
        }
    }
    else if (FWPS_CALLOUT_NOTIFY_DELETE_FILTER == notifyType)
    {
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Delete WFP Filter"
            );
    }
    else if (FWPS_CALLOUT_NOTIFY_ADD_FILTER_POST_COMMIT == notifyType)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Add WFP Filter Post Commit"
            );
    }
    else
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Illegal notifyType = %d",
            notifyType
            );
    }
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! filterId = 0x%016I64X; subLayerWeight = 0x%04hX; flags = 0x%04hX; numFilterConditions = %u;",
        filter->filterId,
        filter->subLayerWeight,
        filter->flags,
        filter->numFilterConditions
        );
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNSFIREWALL,
        "%!FUNC! line:%!LINE! %!LEVEL! action.type = 0x%08X; action.calloutId = 0x%08X; context = %016I64X; providerContext = %p;",
        filter->action.type,
        filter->action.calloutId,
        filter->context,
        filter->providerContext
        );
    return status;
}

void NTAPI onStreamClassify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    FWP_DIRECTION                   enPacketDirection;
    WDFFILEOBJECT                   wdfFlowFileObject = NULL;
    PFLOW_DATA                      pFlowData;
    BOOLEAN                         bInbound;
    BOOLEAN                         bIPv6;
    FWPS_STREAM_CALLOUT_IO_PACKET*  pStreamPacket;
    FWPS_STREAM_DATA0*              pStreamBuffer;
    SIZE_T                          nStreamLength;
    UINT64                          hFlowHandle;
    NTSTATUS                        status;
    WDFREQUEST                      wdfPendedRequest;
    WDFMEMORY                       wdfOutputMemory;
    UINT16                          wMessageLength;
    SIZE_T                          nBytesCopied;
    WDFDEVICE                       wdfDeviceObject;
    WDFQUEUE                        wdfRequestQueue;
    PNET_BUFFER_LIST                pNetBufferList = NULL;
    PMDL                            _pMdl;
    UINT16                          usRemotePort;
    UINT32                          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    BOOLEAN                         bTestIpV4;
    UINT32                          ulInboundCount = 0;
    PLIST_ENTRY                     pListEntry, pLastLE;
    PFLOW_DATA                      pFlowContext = NULL;
    IN6_ADDR                        stRemoteAddress;
    IN_ADDR                         stIpAddress;
    WCHAR                           szIpAddress[128];
    LPWSTR                          pAddressEnd;
    BOOLEAN                         bEmpty;
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(inFixedValues);
    //
    // We don't have the necessary right to alter the classify, exit.
    //
    if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
    {
        //
        // Cannot alter the action.
        //
        return;
    }
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    pStreamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*) layerData;
    ASSERT(NULL != pStreamPacket);
    pStreamBuffer = pStreamPacket->streamData;
    nStreamLength = pStreamBuffer->dataLength;
    pFlowData = (PFLOW_DATA) flowContext;
    ASSERT(NULL != pFlowData);
    ASSERT(pFlowData == pFlowData->pThis);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    bIPv6 = pFlowData->bIPv6;
    bInbound = (BOOLEAN) ((pStreamBuffer->flags & FWPS_STREAM_FLAG_RECEIVE) == FWPS_STREAM_FLAG_RECEIVE);
    enPacketDirection = (bInbound) ? FWP_DIRECTION_INBOUND : FWP_DIRECTION_OUTBOUND;
    pFlowData->enPacketDirection = enPacketDirection;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_FLOW_HANDLE));
    if (0 == nStreamLength)
    {
    _tcp_break_stream:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if (bInbound)
        {
            pFlowData->enContextState = csTcpClientDisconnect;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        else
        {
            pFlowData->enContextState = csTcpServerDisconnect;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        if ((NULL == pFlowData->pTcpResponceInjectBufferList)
            && (NULL == pFlowData->pTcpResponceBufferList)
            && (NULL == pFlowData->pTcpQueryInjectBufferList)
            && (NULL == pFlowData->pTcpQueryBufferList))
        {
            WdfObjectReleaseLock(wdfDeviceObject);
            if (bIPv6)
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_STREAM_V6,
                    g_nStreamIdV6
                    );
            }
            else
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_STREAM_V4,
                    g_nStreamIdV4
                    );
            }
            WdfObjectAcquireLock(wdfDeviceObject);
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
        }
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    hFlowHandle = inMetaValues->flowHandle;
    ASSERT(hFlowHandle == pFlowData->flowHandle);
    switch (pFlowData->enContextState)
    {
    case csTcpFlowEstablished:
        goto _tcp_query_elaborate;
    case csTcpQueryMoreData01:
        goto _tcp_query_elaborate;
    case csTcpQueryMoreData02:
    _tcp_query_elaborate : ;
        ASSERT(bInbound);
        pFlowData->hTcpQueryFlowID = hFlowHandle;
        ASSERT(nStreamLength >= sizeof(UINT16));
        FwpsCopyStreamDataToBuffer(
            pStreamBuffer,
            &wMessageLength,
            sizeof(wMessageLength),
            &nBytesCopied
            );
        ASSERT(nBytesCopied == sizeof(wMessageLength));
        wMessageLength = RtlUshortByteSwap(wMessageLength);
        if (nStreamLength < (SIZE_T) wMessageLength + sizeof(wMessageLength))
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            pStreamPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
            pStreamPacket->countBytesRequired = (UINT32) wMessageLength + sizeof(wMessageLength);
            switch (pFlowData->enContextState)
            {
            case csTcpWaitPermitResponce:
                pFlowData->enContextState = csTcpQueryMoreData02;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpWaitReplaceResponceDone:
                pFlowData->enContextState = csTcpQueryMoreData02;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpQueryMoreData02:
                pFlowData->enContextState = csTcpQueryMoreData02;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpPermitResponceDone:
                pFlowData->enContextState = csTcpQueryMoreData02;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpReplaceResponceDone:
                pFlowData->enContextState = csTcpQueryMoreData02;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpFlowEstablished:
                pFlowData->enContextState = csTcpQueryMoreData01;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpQueryMoreData01:
                pFlowData->enContextState = csTcpQueryMoreData01;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            default:
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Exit (switch (pFlowData->enContextState) default:) enContextState = %u",
                    pFlowData->enContextState
                    );
                pFlowData->enContextState = csTcpQueryMoreData01;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            }
            break;
        }
        if ((SIZE_T) wMessageLength + 2 != nStreamLength)
        {
            bIPv6 = pFlowData->bIPv6;
            if (bIPv6)
            {
                RtlCopyMemory(
                    &stRemoteAddress,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stRemoteAddress)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stRemoteAddress,
                    szIpAddress
                    );
            }
            else
            {
                ulRemoteAddress = pFlowData->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            usRemotePort = pFlowData->usRemotePort;
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Not valid DNS message format! Host %ws; clent.port = %hu; enContextState = %u;",
                szIpAddress,
                usRemotePort,
                pFlowData->enContextState
                );
            goto _tcp_break_stream;
        }
        switch (pFlowData->enContextState)
        {
        case csTcpPermitResponceDone:
        case csTcpReplaceResponceDone:
        case csTcpWaitPermitResponce:
        case csTcpWaitReplaceResponceDone:
        case csTcpQueryMoreData02:
            wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
            break;
        case csTcpFlowEstablished:
        case csTcpQueryMoreData01:
            wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Exit (switch (pFlowData->enContextState) default:) enContextState = %u",
                pFlowData->enContextState
                );
            wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue;
            break;
        }
        ASSERT(NULL != wdfRequestQueue);
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfRequestRetrieveOutputMemory(
            wdfPendedRequest,
            &wdfOutputMemory
            );
        ASSERT(NT_SUCCESS(status));
        switch (pFlowData->enContextState)
        {
        case csTcpPermitResponceDone:
        case csTcpReplaceResponceDone:
        case csTcpWaitPermitResponce:
        case csTcpWaitReplaceResponceDone:
        case csTcpQueryMoreData02:
            pFlowData->wdfWaitTcpNewMessageQueue = NULL;
            break;
        default:
            pFlowData->wdfWaitDnsQueryQueue = NULL;
            break;
        }
        pFlowData->nTcpQueryLength = nStreamLength;
        status = FwpsCloneStreamData(
            pStreamBuffer,
            g_hNetBufferListPool,
            NULL,
            0,
            &pNetBufferList
            );
        ASSERT(NT_SUCCESS(status));
        pFlowData->pTcpQueryBufferList = pNetBufferList;
        switch (pFlowData->enContextState)
        {
        case csTcpWaitPermitResponce:
        case csTcpWaitReplaceResponceDone:
        case csTcpQueryMoreData02:
            pFlowData->enContextState = csTcpWaitResponceInjectDone;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            break;
        case csTcpFlowEstablished:
        case csTcpQueryMoreData01:
        case csTcpPermitResponceDone:
        case csTcpReplaceResponceDone:
            pFlowData->enContextState = csTcpWaitReadQuery;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Exit (switch (pFlowData->enContextState) default:) enContextState = %u",
                pFlowData->enContextState
                );
            pFlowData->enContextState = csTcpWaitReadQuery;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            break;
        }
        status = WdfMemoryCopyFromBuffer(
            wdfOutputMemory,
            0,
            pFlowData,
            sizeof(FLOW_DATA)
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(FLOW_DATA)
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectDelete(wdfRequestQueue);
        break;
    case csTcpPermitQueryDone:
        goto _tcp_responce_elaborate;
    case csTcpReplaceQueryDone:
        goto _tcp_responce_elaborate;
    case csTcpResponceMoreData01:
        goto _tcp_responce_elaborate;
    case csTcpWaitPermitQuery:
        goto _tcp_responce_elaborate;
    case csTcpWaitReplaceQueryDone:
        goto _tcp_responce_elaborate;
    case csTcpResponceMoreData02:
        goto _tcp_responce_elaborate;
    case csTcpResponceMoreData03:
    _tcp_responce_elaborate : ;
        switch (pFlowData->enContextState)
        {
        case csTcpPermitResponceDone:
        case csTcpReplaceResponceDone:
        case csTcpWaitPermitResponce:
        case csTcpWaitReplaceResponceDone:
        case csTcpResponceMoreData03:
            wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
            break;
        default:
            wdfRequestQueue = pFlowData->wdfWaitTcpResponceQueue;
            break;
        }
        ASSERT(NULL != wdfRequestQueue);
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        if (NT_SUCCESS(status))
        {
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            if (pStreamBuffer->flags&FWPS_STREAM_FLAG_SEND)
            {
                bInbound = FALSE;
                enPacketDirection = FWP_DIRECTION_OUTBOUND;
                pFlowData->enPacketDirection = enPacketDirection;
            }
            else
            {   // ! (pStreamBuffer->flags&FWPS_STREAM_FLAG_SEND)
                NTSTATUS    status1;
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Invalid flow direction %!STATUS!",
                    status
                    );
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                switch (pFlowData->enContextState)
                {
                case csTcpPermitQueryDone:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpPermitQueryDone\""
                        );
                    break;
                case csTcpReplaceQueryDone:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpReplaceQueryDone\""
                        );
                    break;
                case csTcpResponceMoreData01:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData01\""
                        );
                    break;
                case csTcpWaitPermitQuery:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitPermitQuery\""
                        );
                    pNetBufferList = pFlowData->pTcpQueryBufferList;
                    if (NULL != pNetBufferList)
                    {
                        FwpsDiscardClonedStreamData(
                            pNetBufferList,
                            0,
                            FALSE
                            );
                        pFlowData->pTcpQueryBufferList = NULL;
                    }
                    break;
                case csTcpWaitReplaceQueryDone:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitReplaceQueryDone\""
                        );
                    pNetBufferList = pFlowData->pTcpQueryInjectBufferList;
                    if (NULL != pNetBufferList)
                    {
                        FwpsFreeNetBufferList(
                            pNetBufferList
                            );
                        pFlowData->pTcpQueryInjectBufferList = NULL;
                        _pMdl = pFlowData->pTcpQueryMdl;
                        ASSERT(NULL != _pMdl);
                        IoFreeMdl(_pMdl);
                        ExFreePoolWithTag(
                            _pMdl->MappedSystemVa,
                            POOL_TAG
                            );
                        pFlowData->pTcpQueryMdl = NULL;
                    }
                    break;
                case csTcpResponceMoreData02:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData02\""
                        );
                    break;
                case csTcpResponceMoreData03:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData03\""
                        );
                    break;
                case csTcpPermitResponceDone:
                    break;
                case csTcpReplaceResponceDone:
                    break;
                case csTcpWaitPermitResponce:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitPermitResponce\""
                        );
                    pNetBufferList = pFlowData->pTcpResponceBufferList;
                    if (NULL != pNetBufferList)
                    {
                        FwpsDiscardClonedStreamData(
                            pNetBufferList,
                            0,
                            FALSE
                            );
                        pFlowData->pTcpResponceBufferList = NULL;
                    }
                    break;
                case csTcpWaitReplaceResponceDone:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitReplaceResponceDone\""
                        );
                    pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
                    if (NULL != pNetBufferList)
                    {
                        FwpsFreeNetBufferList(
                            pNetBufferList
                            );
                        pFlowData->pTcpResponceInjectBufferList = NULL;
                        _pMdl = pFlowData->pTcpResponceMdl;
                        ASSERT(NULL != _pMdl);
                        IoFreeMdl(_pMdl);
                        ExFreePoolWithTag(
                            _pMdl->MappedSystemVa,
                            POOL_TAG
                            );
                        pFlowData->pTcpResponceMdl = NULL;
                    }
                    break;
                default:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine. enContextState = %u",
                        pFlowData->enContextState
                        );
                    break;
                }
                ulInboundCount = 0;
                if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
                {
                    pListEntry = g_stUdpALEAcceptPendedList.Flink;
                    pLastLE = g_stUdpALEAcceptPendedList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (ulInboundCount > 0)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        //ASSERT(FALSE);
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
                {
                    pListEntry = g_stUdpInboundList.Flink;
                    pLastLE = g_stUdpInboundList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (1 == ulInboundCount)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                        pFlowContext->pUdpQuery2BufferList = NULL;
                        pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                        pFlowContext->ulUdpQuery2BufferSize = 0;
                        pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                        pFlowContext->ulUdpQuery2DataOffset = 0;
                        pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                        pFlowContext->ulUdpQuery2PacketOffset = 0;
                        pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                        pFlowContext->ulUdpQuery2DataLength = 0;
                        pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                        pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                        pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                        pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                        pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                        pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        //ASSERT(FALSE);
                        InsertTailList(
                            &g_stUdpALEAcceptPendedList,
                            &pFlowContext->listEntry
                            );
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                pFlowData->enContextState = csTcpIllegalInbound;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                WdfObjectReleaseLock(wdfDeviceObject);
                if (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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectAcquireLock(wdfDeviceObject);
                if ((STATUS_SUCCESS == status) || (STATUS_PENDING == status))
                {
                    WdfObjectReleaseLock(wdfDeviceObject);
                    return;
                }
                pFlowData->enContextState = csDnsError;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                status1 = status;
                wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue;
                pFlowData->wdfWaitFlowDoneQueue = NULL;
                if (NULL != wdfRequestQueue)
                {
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    if (NT_SUCCESS(status))
                    {
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowData,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status1,
                            sizeof(FLOW_DATA)
                            );
                    }
                    WdfObjectDelete(wdfRequestQueue);
                }
                WdfObjectReleaseLock(wdfDeviceObject);
                return;
            }
            // !bInbound
            pFlowData->hTcpResponceFlowID = hFlowHandle;
            ASSERT(nStreamLength >= sizeof(UINT16));
            FwpsCopyStreamDataToBuffer(
                pStreamBuffer,
                &wMessageLength,
                sizeof(wMessageLength),
                &nBytesCopied
                );
            ASSERT(nBytesCopied == sizeof(wMessageLength));
            wMessageLength = RtlUshortByteSwap(wMessageLength);
            if (nStreamLength < (SIZE_T) wMessageLength + 2)
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
                pStreamPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
                pStreamPacket->countBytesRequired = (UINT32) wMessageLength + 2;
                switch (pFlowData->enContextState)
                {
                case csTcpPermitQueryDone:
                    pFlowData->enContextState = csTcpResponceMoreData01;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpReplaceQueryDone:
                    pFlowData->enContextState = csTcpResponceMoreData01;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpPermitResponceDone:
                    pFlowData->enContextState = csTcpResponceMoreData01;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpReplaceResponceDone:
                    pFlowData->enContextState = csTcpResponceMoreData01;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpResponceMoreData01:
                    pFlowData->enContextState = csTcpResponceMoreData01;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpWaitPermitQuery:
                    pFlowData->enContextState = csTcpResponceMoreData02;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpWaitReplaceQueryDone:
                    pFlowData->enContextState = csTcpResponceMoreData02;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpResponceMoreData02:
                    pFlowData->enContextState = csTcpResponceMoreData02;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpWaitPermitResponce:
                    pFlowData->enContextState = csTcpResponceMoreData03;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpWaitReplaceResponceDone:
                    pFlowData->enContextState = csTcpResponceMoreData03;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                case csTcpResponceMoreData03:
                    pFlowData->enContextState = csTcpResponceMoreData03;
                    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                    break;
                default:
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine. enContextState = %u",
                        pFlowData->enContextState
                        );
                    break;
                }
                WdfObjectDelete(wdfRequestQueue);
                break;
            }
            //  !(nStreamLength < (SIZE_T) wMessageLength + 2)
            ASSERT((SIZE_T) wMessageLength + sizeof(wMessageLength) == nStreamLength);
            switch (pFlowData->enContextState)
            {
            case csTcpPermitResponceDone:
            case csTcpReplaceResponceDone:
            case csTcpWaitPermitResponce:
            case csTcpWaitReplaceResponceDone:
            case csTcpResponceMoreData03:
                pFlowData->wdfWaitTcpNewMessageQueue = NULL;
                break;
            default:
                pFlowData->wdfWaitTcpResponceQueue = NULL;
                break;
            }
            pFlowData->nTcpResponceLength = nStreamLength;
            status = FwpsCloneStreamData(
                pStreamBuffer,
                g_hNetBufferListPool,
                NULL,
                0,
                &pFlowData->pTcpResponceBufferList
                );
            ASSERT(NT_SUCCESS(status));
            switch (pFlowData->enContextState)
            {
            case csTcpPermitQueryDone:
                pFlowData->enContextState = csTcpWaitReadResponce;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpReplaceQueryDone:
                pFlowData->enContextState = csTcpWaitReadResponce;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpResponceMoreData01:
                pFlowData->enContextState = csTcpWaitReadResponce;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpPermitResponceDone:
                pFlowData->enContextState = csTcpWaitReadResponce;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpReplaceResponceDone:
                pFlowData->enContextState = csTcpWaitReadResponce;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpWaitPermitQuery:
                pFlowData->enContextState = csTcpWaitQueryInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpWaitReplaceQueryDone:
                pFlowData->enContextState = csTcpWaitQueryInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpResponceMoreData02:
                pFlowData->enContextState = csTcpWaitQueryInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpWaitPermitResponce:
                pFlowData->enContextState = csTcpWaitResponceInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpWaitReplaceResponceDone:
                pFlowData->enContextState = csTcpWaitResponceInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            case csTcpResponceMoreData03:
                pFlowData->enContextState = csTcpWaitResponceInjectDone;
                push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
                break;
            default:
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine. enContextState = %u",
                    pFlowData->enContextState
                    );
                break;
            }
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowData,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectDelete(wdfRequestQueue);
            break;
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
            status
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        switch (pFlowData->enContextState)
        {
        case csTcpPermitQueryDone:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpPermitQueryDone\""
                );
            break;
        case csTcpReplaceQueryDone:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpReplaceQueryDone\""
                );
            break;
        case csTcpResponceMoreData01:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData01\""
                );
            break;
        case csTcpWaitPermitQuery:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitPermitQuery\""
                );
            pNetBufferList = pFlowData->pTcpQueryBufferList;
            if (NULL != pNetBufferList)
            {
                FwpsDiscardClonedStreamData(
                    pNetBufferList,
                    0,
                    FALSE
                    );
                pFlowData->pTcpQueryBufferList = NULL;
            }
            break;
        case csTcpWaitReplaceQueryDone:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitReplaceQueryDone\""
                );
            pNetBufferList = pFlowData->pTcpQueryInjectBufferList;
            if (NULL != pNetBufferList)
            {
                FwpsFreeNetBufferList(
                    pNetBufferList
                    );
                pFlowData->pTcpQueryInjectBufferList = NULL;
                _pMdl = pFlowData->pTcpQueryMdl;
                ASSERT(NULL != _pMdl);
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpQueryMdl = NULL;
            }
            break;
        case csTcpResponceMoreData02:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData02\""
                );
            break;
        case csTcpResponceMoreData03:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpResponceMoreData03\""
                );
            break;
        case csTcpPermitResponceDone:
            break;
        case csTcpReplaceResponceDone:
            break;
        case csTcpWaitPermitResponce:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitPermitResponce\""
                );
            pNetBufferList = pFlowData->pTcpResponceBufferList;
            if (NULL != pNetBufferList)
            {
                FwpsDiscardClonedStreamData(
                    pNetBufferList,
                    0,
                    FALSE
                    );
                pFlowData->pTcpResponceBufferList = NULL;
            }
            break;
        case csTcpWaitReplaceResponceDone:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csTcpWaitReplaceResponceDone\""
                );
            pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
            if (NULL != pNetBufferList)
            {
                FwpsFreeNetBufferList(
                    pNetBufferList
                    );
                pFlowData->pTcpResponceInjectBufferList = NULL;
                _pMdl = pFlowData->pTcpResponceMdl;
                ASSERT(NULL != _pMdl);
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpResponceMdl = NULL;
            }
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine. enContextState = %u",
                pFlowData->enContextState
                );
            break;
        }
        WdfObjectDelete(wdfRequestQueue);
        switch (pFlowData->enContextState)
        {
        case csTcpPermitResponceDone:
        case csTcpReplaceResponceDone:
        case csTcpWaitPermitResponce:
        case csTcpWaitReplaceResponceDone:
        case csTcpResponceMoreData03:
            pFlowData->wdfWaitTcpNewMessageQueue = NULL;
            break;
        default:
            pFlowData->wdfWaitTcpResponceQueue = NULL;
            break;
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowData->enContextState = csDnsError;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        if (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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    case csTcpPermitResponceDone:
        goto _cont15;
    case csTcpReplaceResponceDone:
        goto _cont15;
    case csTcpWaitPermitResponce:
        goto _cont15;
    case csTcpWaitReplaceResponceDone:
    _cont15 :
        if (bInbound)
            goto _tcp_query_elaborate;
        goto _tcp_responce_elaborate;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine. enContextState = %u",
            pFlowData->enContextState
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI onDnsFlowDeletion(
    __in UINT16 layerId,
    __in UINT32 calloutId,
    __in UINT64 flowContext
    )
{
    WDFFILEOBJECT       wdfFlowFileObject;
    PFLOW_DATA          pFlowData;
    WDFREQUEST          wdfPendedRequest = NULL;
    NTSTATUS            status = STATUS_SUCCESS, status1 = STATUS_SUCCESS;
    WDFMEMORY           wdfOutputMemory;
    BOOLEAN             bListEmpty;
    int                 j, nFileIndex, nThreadIndex;
    WDFDEVICE           wdfDeviceObject;
    WDFQUEUE            wdfRequestQueue = NULL;
    PNET_BUFFER_LIST    pNetBufferList;
    PMDL                _pMdl;
    WDFQUEUE            wdfFlowQueue;
    ULONG_PTR           Information;
    WSACMSGHDR*         _pControlData = NULL;
    BOOLEAN             bTestIpV4 = FALSE;
    BOOLEAN             bIPv6;
    UINT32              ulRemoteAddress = 0, ulRemoteAddressN = 0;
    IN_ADDR             stIpAddress;
    WCHAR               szIpAddress[128];
    LPWSTR              pAddressEnd;
    UINT16              usRemotePort;
    IN6_ADDR            stIp6Address;
    IPPROTO             enIpProto;
    UINT32              ulInboundCount;
    PLIST_ENTRY         pListEntry, pLastLE;
    PFLOW_DATA          pFlowContext = NULL;
    IN6_ADDR            stRemoteAddress;
    BOOLEAN             bEmpty;
    UNREFERENCED_PARAMETER(layerId);
    UNREFERENCED_PARAMETER(calloutId);
    pFlowData = (PFLOW_DATA) flowContext;
    if (NULL == pFlowData)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pFlowData)"
            );
        return;
    }
    if (NULL == pFlowData->pThis)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pFlowData->pThis)"
            );
        return;
    }
    if (pFlowData != pFlowData->pThis)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (pFlowData != pFlowData->pThis)"
            );
        return;
    }
    if (0 == pFlowData->flowHandle)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (0 == pFlowData->flowHandle)"
            );
        return;
    }
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    bIPv6 = pFlowData->bIPv6;
    usRemotePort = pFlowData->usRemotePort;
    enIpProto = pFlowData->enIpProto;
    if (!bIPv6)
    {
        ulRemoteAddress = pFlowData->nRemoteAddressV4;
        ulRemoteAddressN = pFlowData->nRemoteAddressV4N;
        bTestIpV4 = ((IPPROTO_UDP == enIpProto) && (c_ulTestIpV4 == ulRemoteAddress));
        if (bTestIpV4)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
        }
    }
    if (pFlowData->bUdpQuery2Reestablish)
    {
        pFlowData->bUdpQuery2Reestablish = FALSE;
        switch (pFlowData->enContextState)
        {
        case csUdpWaitPermitQuery2:
        case csUdpPermitQuery2Done:
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on (pFlowData->bUdpQuery2Reestablish)."
                    );
            }
            WdfObjectReleaseLock(wdfDeviceObject);
            return;
        }
    }
    j = 1;
    pFlowData->enContextState = csFlowDeleted;
    push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
    switch (pFlowData->arContextStateStack[j])
    {
    case csTcpQueryDiscarded:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csTcpWaitApprovalQuery:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csUdpFlowCancel:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowCancel\"."
                );
        }
        j++;
        status1 = STATUS_END_OF_FILE;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpFlowEstablished:
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitReadQuery:
        case csUdpWaitApprovalQuery:
            pNetBufferList = pFlowData->pUdpQueryBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryBufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQueryPended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
               bListEmpty  = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery:
            pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQueryDone:
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce1Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
            pNetBufferList = pFlowData->pUdpResponceBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponceBufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            _pControlData = pFlowData->stUdpResponceSendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce1:
            pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponceCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponceSendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitReadQuery2:
        case csUdpWaitApprovalQuery2:
            pNetBufferList = pFlowData->pUdpQuery2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQuery2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery2:
            pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQuery2Done:
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
            pNetBufferList = pFlowData->pUdpResponce2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce2:
            pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csUdpFlowSetFirewallEvent:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowSetFirewallEvent\"."
                );
        }
        j++;
        status1 = STATUS_NO_MORE_ENTRIES;
        pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpFlowEstablished:
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitReadQuery:
        case csUdpWaitApprovalQuery:
            pNetBufferList = pFlowData->pUdpQueryBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryBufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQueryPended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery:
            pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQueryDone:
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce1Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
            pNetBufferList = pFlowData->pUdpResponceBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponceBufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            _pControlData = pFlowData->stUdpResponceSendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitResponce1:
            pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponceCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponceSendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpWaitReadQuery2:
        case csUdpWaitApprovalQuery2:
            pNetBufferList = pFlowData->pUdpQuery2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            break;
        case csUdpPermitQuery2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery2:
            pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        case csUdpPermitQuery2Done:
            break;
        case csUdpWaitResponce2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
            pNetBufferList = pFlowData->pUdpResponce2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            break;
        case csUdpWaitResponce2:
            pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            break;
        case csUdpFlow1Done:
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csUdpWaitReplaceQuery2:
    case csUdpWaitReplaceQuery:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        j++;
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! UDP Query Replace operation not Implemented on previos Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[j]
            );
        status1 = STATUS_NOT_IMPLEMENTED;
        break;
    case csUdpQuery2Discarded:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpQuery2Discarded\"."
                );
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitApprovalQuery2:
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpQuery2Discarded:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csUdpQueryDiscarded:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpQueryDiscarded\"."
                );
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitApprovalQuery:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csFlowDeleted:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csFlowDeleted\"."
                );
        }
        pNetBufferList = pFlowData->pUdpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
            pFlowData->pUdpQueryBufferList = NULL;
        }
        pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
            pFlowData->pUdpQueryCloneBufferList = NULL;
        }
        pNetBufferList = pFlowData->pUdpQuery2BufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
            pFlowData->pUdpQuery2BufferList = NULL;
        }
        pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
            pFlowData->pUdpQuery2CloneBufferList = NULL;
        }
        pNetBufferList = pFlowData->pTcpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDiscardClonedStreamData(
                pNetBufferList,
                0,
                FALSE
                );
            pFlowData->pTcpQueryBufferList = NULL;
        }
        pNetBufferList = pFlowData->pTcpQueryInjectBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeNetBufferList0(pNetBufferList);
            pFlowData->pTcpQueryInjectBufferList = NULL;
            _pMdl = pFlowData->pTcpQueryMdl;
            if (NULL != _pMdl)
            {
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpQueryMdl = NULL;
            }
        }
        pNetBufferList = pFlowData->pTcpResponceBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDiscardClonedStreamData(
                pNetBufferList,
                0,
                FALSE
                );
            pFlowData->pTcpResponceBufferList = NULL;
        }
        pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeNetBufferList0(pNetBufferList);
            pFlowData->pTcpResponceInjectBufferList = NULL;
            _pMdl = pFlowData->pTcpResponceMdl;
            if (NULL != _pMdl)
            {
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpResponceMdl = NULL;
            }
        }
        pNetBufferList = pFlowData->pUdpResponceBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponceBufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponceCloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        pNetBufferList = pFlowData->pUdpResponce2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2CloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        _pControlData = pFlowData->stUdpResponceSendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponceSendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        status1 = STATUS_END_OF_FILE;
        wdfRequestQueue = pFlowData->wdfTcpResponceInjectQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpResponceInjectQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpResponcePermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpResponcePermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpQueryInjectQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpQueryInjectQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpQueryPermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpQueryPermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpResponceQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpResponceQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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))
            {
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowData,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status1,
                    sizeof(FLOW_DATA)
                    );
            }
            else if (STATUS_NO_MORE_ENTRIES != status)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        bListEmpty = RemoveEntryList(&pFlowData->listEntry);
        if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
        {
            bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
        }
        pFlowData->enContextState = csNotRun;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    case csUdpIllegalOutbound:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpIllegalOutbound\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitResponce1:
        case csUdpWaitResponce2:
        case csUdpWaitResponce2Pended:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Outbound on elaborate DNS UDP Responce."
                );
            status1 = STATUS_UNEXPECTED_NETWORK_ERROR;
            break;
        case csUdpWaitReadQuery:
        case csUdpWaitApprovalQuery:
        case csUdpPermitQueryPended:
        case csUdpWaitPermitQuery:
        case csUdpWaitPermitQuery2:
        case csUdpPermitQuery2Pended:
        case csUdpWaitReplaceQuery2:
        case csUdpQuery2Discarded:
        case csUdpWaitApprovalQuery2:
        case csUdpWaitReadQuery2:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Outbound on elaborate DNS UDP Query."
                );
            status1 = STATUS_UNEXPECTED_NETWORK_ERROR;
            break;
        case csUdpFlowEstablished:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Outbound on First UDP Packet."
                );
            status1 = STATUS_UNEXPECTED_NETWORK_ERROR;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpFlowDone:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowDone\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitResponce2:
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitResponce1:
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpFlow1Done:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        pNetBufferList = pFlowData->pUdpQuery2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQuery2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csTcpClientDisconnect:
    case csTcpServerDisconnect:
        status1 = STATUS_END_OF_FILE;
        pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeNetBufferList0(pNetBufferList);
            pFlowData->pTcpResponceInjectBufferList = NULL;
            _pMdl = pFlowData->pTcpResponceMdl;
            if (NULL != _pMdl)
            {
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpResponceMdl = NULL;
            }
        }
        pNetBufferList = pFlowData->pTcpResponceBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDiscardClonedStreamData(
                pNetBufferList,
                0,
                FALSE
                );
            pFlowData->pTcpResponceBufferList = NULL;
        }
        pNetBufferList = pFlowData->pTcpQueryInjectBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsFreeNetBufferList0(pNetBufferList);
            pFlowData->pTcpQueryInjectBufferList = NULL;
            _pMdl = pFlowData->pTcpQueryMdl;
            if (NULL != _pMdl)
            {
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpQueryMdl = NULL;
            }
        }
        pNetBufferList = pFlowData->pTcpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            FwpsDiscardClonedStreamData(
                pNetBufferList,
                0,
                FALSE
                );
            pFlowData->pTcpQueryBufferList = NULL;
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpResponceQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpResponceQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpQueryPermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpQueryPermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpQueryInjectQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpQueryInjectQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpResponcePermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpResponcePermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfTcpResponceInjectQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpResponceInjectQueue = 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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpSetFilterEvent:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpSetFilterEvent\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitReadQuery2:
        case csUdpWaitApprovalQuery2:
        case csUdpQuery2Discarded:
        case csUdpWaitReplaceQuery2:
        case csUdpPermitQuery2Pended:
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpPermitQuery2Done:
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitResponce2Pended:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        wdfRequestQueue = pFlowData->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitFlowDoneQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            if (NT_SUCCESS(status))
            {
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    STATUS_NO_MORE_ENTRIES,
                    0
                    );
            }
            else if (STATUS_NO_MORE_ENTRIES != status)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL;
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfRequestRetrieveOutputMemory(
            wdfPendedRequest,
            &wdfOutputMemory
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfMemoryCopyFromBuffer(
            wdfOutputMemory,
            0,
            pFlowData,
            sizeof(FLOW_DATA)
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(FLOW_DATA)
            );
        WdfObjectDelete(wdfRequestQueue);
        break;
    case csTcpIllegalInbound:
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csTcpPermitQueryDone:
        case csTcpReplaceQueryDone:
        case csTcpResponceMoreData01:
        case csTcpWaitPermitQuery:
        case csTcpWaitReplaceQueryDone:
        case csTcpResponceMoreData02:
        case csTcpResponceMoreData03:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Inbound on elaborate DNS TCP Responce."
                );
            status1 = STATUS_UNEXPECTED_NETWORK_ERROR;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csTcpReplaceResponceDone:
        status1 = STATUS_END_OF_FILE;
        wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csTcpReplaceResponcePended:
        status1 = STATUS_END_OF_FILE;
        if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
        {
            bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
        }
        pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pTcpResponceInjectBufferList = NULL;
            FwpsFreeNetBufferList0(pNetBufferList);
            _pMdl = pFlowData->pTcpResponceMdl;
            if (NULL != _pMdl)
            {
                IoFreeMdl(_pMdl);
                ExFreePoolWithTag(
                    _pMdl->MappedSystemVa,
                    POOL_TAG
                    );
                pFlowData->pTcpResponceMdl = NULL;
            }
        }
        wdfRequestQueue = pFlowData->wdfTcpResponceInjectQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfTcpResponceInjectQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            if (NT_SUCCESS(status))
            {
                Information = pFlowData->nTcpResponceInjectDataSize;
                pFlowData->nTcpResponceInjectDataSize = 0;
                ASSERT(0 != Information);
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    STATUS_END_OF_FILE,
                    Information
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
            else if (STATUS_NO_MORE_ENTRIES != status)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csTcpPermitQueryDone:
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csTcpWaitPermitQuery:
        case csTcpPermitQueryDone:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpPermitQueryDone:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQueryDone\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitPermitQuery:
            status1 = STATUS_END_OF_FILE;
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpPermitQuery2Done:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQuery2Done\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitPermitQuery2:
            status1 = STATUS_END_OF_FILE;
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpWaitResponce1Pended:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce1Pended\"."
                );
        }
        if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
        {
            bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
        }
        pNetBufferList = pFlowData->pUdpResponceBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponceBufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        _pControlData = pFlowData->stUdpResponceSendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponceSendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        status1 = STATUS_END_OF_FILE;
        break;
    case csUdpWaitResponce1:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce1\"."
                );
        }
        pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponceCloneBufferList = NULL;
            //if (pFlowData->arContextStateStack[2] != csUdpWaitResponce1Pended)
            //{
            //    FwpsFreeCloneNetBufferList(
            //        pNetBufferList,
            //        0
            //        );
            //}
        }
        _pControlData = pFlowData->stUdpResponceSendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponceSendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        status1 = STATUS_END_OF_FILE;
        break;
    case csUdpWaitPermitQuery2:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitPermitQuery2\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpWaitPermitQuery:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpWaitResponce2Pended:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2Pended\"."
                );
        }
        if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
        {
            bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
        }
        pNetBufferList = pFlowData->pUdpResponce2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponce2SendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        status1 = STATUS_END_OF_FILE;
        break;
    case csUdpWaitResponce2:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2\"."
                );
        }
        pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2CloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponce2SendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpFiltersChangeInProgress:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFiltersChangeInProgress\"."
                );
        }
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csUdpFlowEstablished:
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitReadQuery:
        case csUdpWaitApprovalQuery:
            pNetBufferList = pFlowData->pUdpQueryBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryBufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpPermitQueryPended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery:
            pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQueryCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpPermitQueryDone:
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitReadQuery2:
        case csUdpWaitApprovalQuery2:
            pNetBufferList = pFlowData->pUdpQuery2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpPermitQuery2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
        case csUdpWaitPermitQuery2:
            pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpQuery2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
            if (NULL != wdfRequestQueue)
            {
                pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpPermitQuery2Done:
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitResponce2:
            pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2CloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitResponce1:
            pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponceCloneBufferList = NULL;
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
            _pControlData = pFlowData->stUdpResponceSendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        case csUdpWaitResponce2Pended:
            if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
            {
                bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
            }
            pNetBufferList = pFlowData->pUdpResponce2BufferList;
            if (NULL != pNetBufferList)
            {
                pFlowData->pUdpResponce2BufferList = NULL;
                FwpsDereferenceNetBufferList(
                    pNetBufferList,
                    FALSE
                    );
            }
            _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
            if (NULL != _pControlData)
            {
                ExFreePoolWithTag(
                    _pControlData,
                    POOL_TAG
                    );
            }
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams,
                sizeof(FWPS_TRANSPORT_SEND_PARAMS)
                );
            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_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                        status
                        );
                }
                WdfObjectDelete(wdfRequestQueue);
            }
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            //ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        break;
    case csTcpReplaceQueryDone:
        j++;
        switch (pFlowData->arContextStateStack[j])
        {
        case csTcpWaitReplaceQueryDone:
            status1 = STATUS_END_OF_FILE;
            break;
        default:
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u",
                (UINT32) pFlowData->arContextStateStack[j]
                );
            ////ASSERT(FALSE);
            status1 = STATUS_UNEXPECTED_IO_ERROR;
        }
        wdfRequestQueue = pFlowData->wdfWaitTcpResponceQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpResponceQueue = 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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csTcpWaitReplaceResponceDone:
    case csTcpQueryMoreData01:
    case csTcpQueryMoreData02:
    case csTcpWaitReadQuery:
    case csTcpWaitApprovalQuery:
    case csTcpWaitResponceStarted:
    case csTcpWaitReplaceQuery:
    case csTcpPermitQueryPended:
    case csTcpWaitPermitQuery:
    case csTcpWaitQueryInjectDone:
    case csTcpReplaceQueryPended:
    case csTcpWaitReplaceQueryDone:
    case csTcpWaitReadResponce:
    case csTcpResponceMoreData01:
    case csTcpResponceMoreData02:
    case csTcpResponceMoreData03:
    case csTcpWaitApprovalResponce:
    case csTcpPermitResponcePended:
    case csTcpWaitPermitResponce:
    case csTcpPermitResponceDone:
    case csTcpWaitResponceInjectDone:
    case csTcpWaitReplaceResponce:
    case csTcpResponceDiscarded:
    case csTcpWaitNewMessageStarted:
        status1 = STATUS_END_OF_FILE;
        wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csTcpFlowEstablished:
        status1 = STATUS_END_OF_FILE;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! DNS Packets Flow terminated on state \"csTcpFlowEstablished\""
            );
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpFlowEstablished:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowEstablished\"."
                );
        }
        status1 = STATUS_END_OF_FILE;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! DNS Packets Flow terminated on state \"csUdpFlowEstablished\""
            );
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpWaitReadQuery:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitReadQuery\"."
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow Terminated on state \"csUdpWaitReadQuery\"!"
            );
        pNetBufferList = pFlowData->pUdpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQueryBufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        status1 = STATUS_END_OF_FILE;
        break;
    case csUdpFlowBreak:
        j++;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowBreak\"."
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host has previos state = %u.",
                pFlowData->arContextStateStack[j]
                );
        }
        status1 = STATUS_END_OF_FILE;
        if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
        {
            bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
        }
        pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2CloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponce2SendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        pNetBufferList = pFlowData->pUdpResponce2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponce2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQuery2CloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        pNetBufferList = pFlowData->pUdpQuery2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQuery2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpResponceCloneBufferList = NULL;
            if (!(pFlowData->arContextStateStack[1] == csUdpFlowBreak && pFlowData->arContextStateStack[2] == csUdpWaitResponce1))
            {
                FwpsFreeCloneNetBufferList(
                    pNetBufferList,
                    0
                    );
            }
        }
        _pControlData = pFlowData->stUdpResponceSendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponceSendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQueryCloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        pNetBufferList = pFlowData->pUdpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQueryBufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    case csUdpWaitPermitQuery:
        status1 = STATUS_END_OF_FILE;
        pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowData->pUdpQueryCloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                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_DNSFIREWALL,
                    "%!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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        break;
    default:
        if (bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Illegal Driver State = %u!!  Host %ws; clent.port = %hu;",
            (UINT32) pFlowData->arContextStateStack[j],
            szIpAddress,
            usRemotePort
            );
        //ASSERT(FALSE);
        status1 = STATUS_UNEXPECTED_IO_ERROR;
    }
    bListEmpty = RemoveEntryList(&pFlowData->listEntry);
    nFileIndex = pFlowData->nFileIndex;
    nThreadIndex = pFlowData->nThreadIndex;
    if (IsListEntryInList(&pFlowData->threadListEntry, &g_stPendedPacketsQueue))
    {
        bListEmpty = RemoveEntryList(&pFlowData->threadListEntry);
    }
    wdfFlowQueue = pFlowData->wdfFlowQueue;
    pNetBufferList = pFlowData->pTcpResponceInjectBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pTcpResponceInjectBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsFreeNetBufferList0(pNetBufferList);
        pFlowData->pTcpResponceInjectBufferList = NULL;
        _pMdl = pFlowData->pTcpResponceMdl;
        if (NULL != _pMdl)
        {
            IoFreeMdl(_pMdl);
            ExFreePoolWithTag(
                _pMdl->MappedSystemVa,
                POOL_TAG
                );
            pFlowData->pTcpResponceMdl = NULL;
        }
    }
    pNetBufferList = pFlowData->pTcpResponceBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pTcpResponceBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsDiscardClonedStreamData(
            pNetBufferList,
            0,
            FALSE
            );
        pFlowData->pTcpResponceBufferList = NULL;
    }
    pNetBufferList = pFlowData->pTcpQueryInjectBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pTcpQueryInjectBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsFreeNetBufferList0(pNetBufferList);
        pFlowData->pTcpQueryInjectBufferList = NULL;
        _pMdl = pFlowData->pTcpQueryMdl;
        if (NULL != _pMdl)
        {
            IoFreeMdl(_pMdl);
            ExFreePoolWithTag(
                _pMdl->MappedSystemVa,
                POOL_TAG
                );
            pFlowData->pTcpQueryMdl = NULL;
        }
    }
    pNetBufferList = pFlowData->pTcpQueryBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pTcpQueryBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsDiscardClonedStreamData(
            pNetBufferList,
            0,
            FALSE
            );
        pFlowData->pTcpQueryBufferList = NULL;
    }
    pNetBufferList = pFlowData->pUdpResponce2CloneBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpResponce2CloneBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->pUdpResponce2CloneBufferList = NULL;
        FwpsFreeCloneNetBufferList(
            pNetBufferList,
            0
            );
    }
    _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
    if (NULL != _pControlData)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"stUdpResponce2SendParams.controlData\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        ExFreePoolWithTag(
            _pControlData,
            POOL_TAG
            );
    }
    RtlZeroMemory(
        &pFlowData->stUdpResponce2SendParams,
        sizeof(FWPS_TRANSPORT_SEND_PARAMS)
        );
    pNetBufferList = pFlowData->pUdpResponce2BufferList;
    if (NULL != pNetBufferList)
    {
        pFlowData->pUdpResponce2BufferList = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpResponce2BufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsDereferenceNetBufferList(
            pNetBufferList,
            FALSE
            );
    }
    pNetBufferList = pFlowData->pUdpQuery2CloneBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpQuery2CloneBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->pUdpQuery2CloneBufferList = NULL;
        FwpsFreeCloneNetBufferList(
            pNetBufferList,
            0
            );
    }
    pNetBufferList = pFlowData->pUdpQuery2BufferList;
    if (NULL != pNetBufferList)
    {
        pFlowData->pUdpQuery2BufferList = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpQuery2BufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsDereferenceNetBufferList(
            pNetBufferList,
            FALSE
            );
    }
    pNetBufferList = pFlowData->pUdpResponceCloneBufferList;
    if (NULL != pNetBufferList)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpResponceCloneBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->pUdpResponceCloneBufferList = NULL;
        FwpsFreeCloneNetBufferList(
            pNetBufferList,
            0
            );
    }
    _pControlData = pFlowData->stUdpResponceSendParams.controlData;
    if (NULL != _pControlData)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"stUdpResponceSendParams.controlData\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        ExFreePoolWithTag(
            _pControlData,
            POOL_TAG
            );
    }
    RtlZeroMemory(
        &pFlowData->stUdpResponceSendParams,
        sizeof(FWPS_TRANSPORT_SEND_PARAMS)
        );
    pNetBufferList = pFlowData->pUdpQueryCloneBufferList;
    if (NULL != pNetBufferList)
    {
        pFlowData->pUdpQueryCloneBufferList = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpQueryCloneBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsFreeCloneNetBufferList(
            pNetBufferList,
            0
            );
    }
    pNetBufferList = pFlowData->pUdpQueryBufferList;
    if (NULL != pNetBufferList)
    {
        pFlowData->pUdpQueryBufferList = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"pUdpQueryBufferList\" not free; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        FwpsDereferenceNetBufferList(
            pNetBufferList,
            FALSE
            );
    }
    wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue;
    if (NULL != wdfRequestQueue)
    {
        pFlowData->wdfWaitUdpQuery2Queue = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfWaitUdpQuery2Queue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue;
    if (NULL != wdfRequestQueue)
    {
        pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfWaitUdpSetFirewallFilterQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue;
    if (NULL != wdfRequestQueue)
    {
        pFlowData->wdfWaitDnsQueryQueue = NULL;
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfWaitDnsQueryQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfUdpQueryPermitQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfUdpQueryPermitQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfUdpQuery2PermitQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfUdpQuery2PermitQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfWaitTcpNewMessageQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfWaitTcpNewMessageQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfWaitTcpNewMessageQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfWaitTcpResponceQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfWaitTcpResponceQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfWaitTcpResponceQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfTcpQueryPermitQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfTcpQueryPermitQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfTcpQueryPermitQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfTcpQueryInjectQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfTcpQueryInjectQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfTcpQueryInjectQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfTcpResponcePermitQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfTcpResponcePermitQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfTcpResponcePermitQueue = 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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    wdfRequestQueue = pFlowData->wdfTcpResponceInjectQueue;
    if (NULL != wdfRequestQueue)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"wdfTcpResponceInjectQueue\" not empty; Driver State = %u",
            (UINT32) pFlowData->arContextStateStack[1]
            );
        pFlowData->wdfTcpResponceInjectQueue = 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_DNSFIREWALL,
                "%!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))
        {
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowData,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status1,
                sizeof(FLOW_DATA)
                );
        }
        else if (STATUS_NO_MORE_ENTRIES != status)
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                status
                );
        }
        WdfObjectDelete(wdfRequestQueue);
    }
    RtlZeroMemory(
        pFlowData,
        sizeof(FLOW_DATA)
        );
    pFlowData->pThis = pFlowData;
    pFlowData->nFileIndex = nFileIndex;
    pFlowData->nThreadIndex = nThreadIndex;
    pFlowData->wdfFlowFileObject = wdfFlowFileObject;
    pFlowData->wdfFlowQueue = wdfFlowQueue;
    if (IsListHeadBad(&g_stFreeFileList))
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid \"g_stFreeFileList\"!!"
            );
        InitializeListHead(&g_stFreeFileList);
    }
    pFlowData->enFlowDataOwner = foFreeFileList;
    push_fos(pFlowData->arFlowDataOwnerStack, pFlowData->enFlowDataOwner);
    InsertTailList(
        &g_stFreeFileList,
        &pFlowData->listEntry
        );
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI onDatagramDataClassify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    FWP_DIRECTION               enPacketDirection;
    WDFFILEOBJECT               wdfFlowFileObject = NULL;
    WDFFILEOBJECT               wdfInjectDataObject = NULL;
    NTSTATUS                    status = STATUS_SUCCESS;
    BOOLEAN                     bInbound;
    BOOLEAN                     bIPv6;
    PNET_BUFFER_LIST            pNetBufferList;
    FWPS_PACKET_INJECTION_STATE packetState;
    PFLOW_DATA                  pFlowData;
    PNET_BUFFER                 pNetBuffer;
    UINT32                      nDataSize;
    UINT32                      ulUdpDataOffset;
    UINT32                      ulUdpDataLength;
    UINT32                      ulIpHeaderSize;
    UINT32                      ulTransportHeaderSize;
    WDFREQUEST                  wdfPendedRequest;
    WDFMEMORY                   wdfOutputMemory = NULL;
    COMPARTMENT_ID              enUdpCompartmentID;
    WDFDEVICE                   wdfDeviceObject;
    WDFQUEUE                    wdfRequestQueue;
    UINT64                      hFlowHandle;
    HANDLE                      hInjectionHandle;
    IN6_ADDR                    stIp6Address;
    IN_ADDR                     stIpAddress;
    WCHAR                       szIpAddress[128];
    LPWSTR                      pAddressEnd;
    BOOLEAN                     bSignalWorkerThread;
    UINT16                      usRemotePort;
    UINT32                      ulRemoteAddress = 0, ulRemoteAddressN = 0;
    BOOLEAN                     bTestIpV4;
    UINT32                      ulInboundCount = 0;
    PLIST_ENTRY                 pListEntry, pLastLE, pNextLE;
    PFLOW_DATA                  pFlowContext = NULL;
    IN6_ADDR                    stRemoteAddress;
    BOOLEAN                     bEmpty;
    FWP_BYTE_ARRAY16            *pRemoteAddress = NULL;
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(filter);
    //
    // We don't have the necessary right to alter the classify, exit.
    //
    if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
    {
        //
        // Cannot alter the action.
        //
        return;
    }
    pNetBufferList = (PNET_BUFFER_LIST) layerData;
    ASSERT(pNetBufferList != NULL);
    pFlowData = (PFLOW_DATA) flowContext;
    ASSERT(NULL != pFlowData);
    ASSERT(pFlowData == pFlowData->pThis);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    bIPv6 = pFlowData->bIPv6;
    if (bIPv6)
    {
        hInjectionHandle = g_hInjectionHandleV6;
        enPacketDirection = (FWP_DIRECTION) inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].value.uint8;
    }
    else
    {
        ulRemoteAddress = pFlowData->nRemoteAddressV4;
        hInjectionHandle = g_hInjectionHandleV4;
        enPacketDirection = (FWP_DIRECTION) inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint8;
    }
    bInbound = (BOOLEAN) (FWP_DIRECTION_INBOUND == enPacketDirection);
    WdfObjectAcquireLock(wdfDeviceObject);
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_FLOW_HANDLE));
    hFlowHandle = inMetaValues->flowHandle;
    if (hFlowHandle != pFlowData->flowHandle)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! Exit (hFlowHandle != pFlowData->flowHandle)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    pFlowData->enPacketDirection = enPacketDirection;
    if (bInbound && (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked))
    {
        if (bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)!",
            szIpAddress
            );
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            ulInboundCount = 0;
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowData->enContextState = csUdpFiltersChangeInProgress;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        if (bIPv6)
        {
            status = FwpsFlowRemoveContext(
                pFlowData->flowHandle,
                FWPS_LAYER_DATAGRAM_DATA_V6,
                g_nDatagramIdV6
                );
        }
        else
        {
            status = FwpsFlowRemoveContext(
                pFlowData->flowHandle,
                FWPS_LAYER_DATAGRAM_DATA_V4,
                g_nDatagramIdV4
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    }
    if (bIPv6)
    {
        pRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16;
        pFlowData->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32;
        pFlowData->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].value.uint32;
        usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_PORT].value.uint16;
    }
    else
    {
        pFlowData->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
        pFlowData->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
        ulRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32;
        usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16;
        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
    }
    pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
    nDataSize = NET_BUFFER_DATA_LENGTH(pNetBuffer);
    ulUdpDataOffset = NET_BUFFER_DATA_OFFSET(pNetBuffer);
    enUdpCompartmentID = (COMPARTMENT_ID) inMetaValues->compartmentId;
    if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE))
    {
        ulIpHeaderSize = inMetaValues->ipHeaderSize;
    }
    else
    {
        ulIpHeaderSize = pFlowData->ulUdpQueryIpHeaderSize;
    }
    ulTransportHeaderSize = inMetaValues->transportHeaderSize;
    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
    if (bTestIpV4)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
    }
    packetState = FwpsQueryPacketInjectionState(
        hInjectionHandle,
        pNetBufferList,
        (HANDLE*) &wdfInjectDataObject
        );
    if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
    {
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Reinjected."
                );
        }
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    usRemotePort = pFlowData->usRemotePort;
    switch (pFlowData->enContextState)
    {
    case csUdpFlowEstablished:
        if (!bInbound)
        {
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! if (!bInbound)! Host IP = %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(wdfDeviceObject);
            break;
        }
        // inbound
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowEstablished\"."
                );
        }
        pFlowData->ulUdpQueryCount++;
        pFlowData->pUdpQueryBufferList = pNetBufferList;
        pFlowData->ulUdpQueryBufferSize = nDataSize + ulIpHeaderSize + ulTransportHeaderSize;
        pFlowData->ulUdpQueryDataOffset = ulUdpDataOffset;
        pFlowData->ulUdpQueryPacketOffset = ulUdpDataOffset - ulIpHeaderSize - ulTransportHeaderSize;
        ulUdpDataLength = nDataSize;
        pFlowData->ulUdpQueryDataLength = ulUdpDataLength;
        ASSERT(pFlowData->ulUdpQueryDataLength > 0);
        pFlowData->enUdpQueryCompartmentID = enUdpCompartmentID;
        pFlowData->ulUdpQueryIpHeaderSize = ulIpHeaderSize;
        pFlowData->ulUdpQueryTransportHeaderSize = ulTransportHeaderSize;
        FwpsReferenceNetBufferList(pNetBufferList, TRUE);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        pFlowData->enContextState = csUdpWaitReadQuery;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        wdfRequestQueue = pFlowData->wdfWaitDnsQueryQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfWaitDnsQueryQueue = NULL;
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfRequestRetrieveOutputMemory(
            wdfPendedRequest,
            &wdfOutputMemory
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfMemoryCopyFromBuffer(
            wdfOutputMemory,
            0,
            pFlowData,
            sizeof(FLOW_DATA)
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(FLOW_DATA)
            );
        WdfObjectDelete(wdfRequestQueue);
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    case csUdpWaitResponce1Pended:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        if (bInbound)
        {
            if (pFlowData->bUdpQueryClassifyPended)
            {
                pFlowData->bUdpQueryClassifyPended = FALSE;
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query from host %ws; clent.port = %hu;",
                    szIpAddress,
                    pFlowData->usRemotePort
                    );
                //ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                break;
            }
            if ((usRemotePort != pFlowData->usRemotePort)
                && (!IsListEmpty(&g_stUdpAcceptNotifyList)))
            {
                ulInboundCount = 0;
                pListEntry = g_stUdpAcceptNotifyList.Flink;
                pLastLE = g_stUdpAcceptNotifyList.Blink;
                for (;;)
                {
                    pNextLE = pListEntry->Flink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            ulInboundCount++;
                            break;
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            ulInboundCount++;
                            break;
                        }
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pNextLE;
                }
                if (ulInboundCount > 0)
                {
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    pFlowContext->bIPv6 = FALSE;
                    pFlowContext->bUdpNotifyQuery = FALSE;
                    pFlowContext->enContextState = csWaitQueryStarted;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foAcceptableList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    InsertTailList(
                        &g_stAcceptableList,
                        &pFlowContext->listEntry
                        );
                    ulInboundCount = 0;
                    if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
                    {
                        pListEntry = g_stUdpALEAcceptPendedList.Flink;
                        pLastLE = g_stUdpALEAcceptPendedList.Blink;
                        for (;;)
                        {
                            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                            ASSERT(pFlowContext == pFlowContext->pThis);
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ulInboundCount++;
                                break;
                            }
                            if (pListEntry == pLastLE)
                            {
                                break;
                            }
                            pListEntry = pListEntry->Flink;
                        }
                        if (ulInboundCount > 0)
                        {
                            bIPv6 = pFlowContext->bIPv6;
                            if (bIPv6)
                            {
                                RtlCopyMemory(
                                    &stRemoteAddress,
                                    &pFlowContext->stRemoteAddressV6,
                                    sizeof(stRemoteAddress)
                                    );
                            }
                            else
                            {
                                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            }
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                            if (bTestIpV4)
                            {
                                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                                pAddressEnd = RtlIpv4AddressToStringW(
                                    &stIpAddress,
                                    szIpAddress
                                    );
                                TraceEvents(
                                    TRACE_LEVEL_INFORMATION,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                                    szIpAddress,
                                    usRemotePort
                                    );
                            }
                            pFlowContext->bUdpQueryClassifyPended = TRUE;
                            pFlowContext->ulUdpQueryCount++;
                            pFlowContext->enContextState = csUdpWaitReadQuery;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            //ASSERT(FALSE);
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitDnsQueryQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfRequestRetrieveOutputMemory(
                                wdfPendedRequest,
                                &wdfOutputMemory
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfMemoryCopyFromBuffer(
                                wdfOutputMemory,
                                0,
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            ASSERT(NT_SUCCESS(status));
                            WdfRequestCompleteWithInformation(
                                wdfPendedRequest,
                                status,
                                sizeof(FLOW_DATA)
                                );
                            WdfObjectDelete(wdfRequestQueue);
                        }
                    }
                    if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
                    {
                        pListEntry = g_stUdpInboundList.Flink;
                        pLastLE = g_stUdpInboundList.Blink;
                        for (;;)
                        {
                            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                            ASSERT(pFlowContext == pFlowContext->pThis);
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ulInboundCount++;
                                break;
                            }
                            if (pListEntry == pLastLE)
                            {
                                break;
                            }
                            pListEntry = pListEntry->Flink;
                        }
                        if (1 == ulInboundCount)
                        {
                            bIPv6 = pFlowContext->bIPv6;
                            if (bIPv6)
                            {
                                RtlCopyMemory(
                                    &stRemoteAddress,
                                    &pFlowContext->stRemoteAddressV6,
                                    sizeof(stRemoteAddress)
                                    );
                            }
                            else
                            {
                                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            }
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                            if (bTestIpV4)
                            {
                                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                                pAddressEnd = RtlIpv4AddressToStringW(
                                    &stIpAddress,
                                    szIpAddress
                                    );
                                TraceEvents(
                                    TRACE_LEVEL_INFORMATION,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                                    szIpAddress,
                                    usRemotePort
                                    );
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                            pFlowContext->bUdpQueryClassifyPended = TRUE;
                            pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                            pFlowContext->ulUdpQueryCount++;
                            pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                            pFlowContext->pUdpQuery2BufferList = NULL;
                            pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                            pFlowContext->ulUdpQuery2BufferSize = 0;
                            pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                            pFlowContext->ulUdpQuery2DataOffset = 0;
                            pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                            pFlowContext->ulUdpQuery2PacketOffset = 0;
                            pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                            pFlowContext->ulUdpQuery2DataLength = 0;
                            pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                            pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                            pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                            pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                            pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                            pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                            pFlowContext->enContextState = csUdpWaitReadQuery;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            //ASSERT(FALSE);
                            InsertTailList(
                                &g_stUdpALEAcceptPendedList,
                                &pFlowContext->listEntry
                                );
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitDnsQueryQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfRequestRetrieveOutputMemory(
                                wdfPendedRequest,
                                &wdfOutputMemory
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfMemoryCopyFromBuffer(
                                wdfOutputMemory,
                                0,
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            ASSERT(NT_SUCCESS(status));
                            WdfRequestCompleteWithInformation(
                                wdfPendedRequest,
                                status,
                                sizeof(FLOW_DATA)
                                );
                            WdfObjectDelete(wdfRequestQueue);
                        }
                    }
                    classifyOut->actionType = FWP_ACTION_PERMIT;
                    WdfObjectReleaseLock(wdfDeviceObject);
                    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
                            );
                    }
                    if (!NT_SUCCESS(status))
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                            status
                            );
                    }
                    break;
                }
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound
        KeClearEvent(&g_oWorkerEvent);
        if (IsListHeadBad(&g_stPendedPacketsQueue))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Invalid \"g_stPendedPacketsQueue\"!!"
                );
            InitializeListHead(&g_stPendedPacketsQueue);
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Double send responce #1 to host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        pFlowData->enContextState = csUdpFlowBreak;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        break;
    case csUdpWaitResponce1:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        if (bInbound)
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Invalid INBOUND Datagram on state \"csUdpWaitResponce1\" from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid OUTBOUND Datagram on state \"csUdpWaitResponce1\" to host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        pFlowData->enContextState = csUdpFlowBreak;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        break;
    case csUdpPermitQueryDone:
        if (bInbound)
        {
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            if (pFlowData->bUdpQueryClassifyPended)
            {
                pFlowData->bUdpQueryClassifyPended = FALSE;
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query from host %ws; clent.port = %hu;",
                    szIpAddress,
                    pFlowData->usRemotePort
                    );
                //ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                break;
            }
            if ((usRemotePort != pFlowData->usRemotePort)
                && (!IsListEmpty(&g_stUdpAcceptNotifyList)))
            {
                ulInboundCount = 0;
                pListEntry = g_stUdpAcceptNotifyList.Flink;
                pLastLE = g_stUdpAcceptNotifyList.Blink;
                for (;;)
                {
                    pNextLE = pListEntry->Flink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            ulInboundCount++;
                            break;
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            ulInboundCount++;
                            break;
                        }
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pNextLE;
                }
                if (ulInboundCount > 0)
                {
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    pFlowContext->bIPv6 = FALSE;
                    pFlowContext->bUdpNotifyQuery = FALSE;
                    pFlowContext->enContextState = csWaitQueryStarted;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foAcceptableList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    InsertTailList(
                        &g_stAcceptableList,
                        &pFlowContext->listEntry
                        );
                    ulInboundCount = 0;
                    if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
                    {
                        pListEntry = g_stUdpALEAcceptPendedList.Flink;
                        pLastLE = g_stUdpALEAcceptPendedList.Blink;
                        for (;;)
                        {
                            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                            ASSERT(pFlowContext == pFlowContext->pThis);
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ulInboundCount++;
                                break;
                            }
                            if (pListEntry == pLastLE)
                            {
                                break;
                            }
                            pListEntry = pListEntry->Flink;
                        }
                        if (ulInboundCount > 0)
                        {
                            bIPv6 = pFlowContext->bIPv6;
                            if (bIPv6)
                            {
                                RtlCopyMemory(
                                    &stRemoteAddress,
                                    &pFlowContext->stRemoteAddressV6,
                                    sizeof(stRemoteAddress)
                                    );
                            }
                            else
                            {
                                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            }
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                            if (bTestIpV4)
                            {
                                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                                pAddressEnd = RtlIpv4AddressToStringW(
                                    &stIpAddress,
                                    szIpAddress
                                    );
                                TraceEvents(
                                    TRACE_LEVEL_INFORMATION,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                                    szIpAddress,
                                    usRemotePort
                                    );
                            }
                            pFlowContext->bUdpQueryClassifyPended = TRUE;
                            pFlowContext->ulUdpQueryCount++;
                            pFlowContext->enContextState = csUdpWaitReadQuery;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            //ASSERT(FALSE);
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitDnsQueryQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfRequestRetrieveOutputMemory(
                                wdfPendedRequest,
                                &wdfOutputMemory
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfMemoryCopyFromBuffer(
                                wdfOutputMemory,
                                0,
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            ASSERT(NT_SUCCESS(status));
                            WdfRequestCompleteWithInformation(
                                wdfPendedRequest,
                                status,
                                sizeof(FLOW_DATA)
                                );
                            WdfObjectDelete(wdfRequestQueue);
                        }
                    }
                    if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
                    {
                        pListEntry = g_stUdpInboundList.Flink;
                        pLastLE = g_stUdpInboundList.Blink;
                        for (;;)
                        {
                            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                            ASSERT(pFlowContext == pFlowContext->pThis);
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ulInboundCount++;
                                break;
                            }
                            if (pListEntry == pLastLE)
                            {
                                break;
                            }
                            pListEntry = pListEntry->Flink;
                        }
                        if (1 == ulInboundCount)
                        {
                            bIPv6 = pFlowContext->bIPv6;
                            if (bIPv6)
                            {
                                RtlCopyMemory(
                                    &stRemoteAddress,
                                    &pFlowContext->stRemoteAddressV6,
                                    sizeof(stRemoteAddress)
                                    );
                            }
                            else
                            {
                                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            }
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                            if (bTestIpV4)
                            {
                                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                                pAddressEnd = RtlIpv4AddressToStringW(
                                    &stIpAddress,
                                    szIpAddress
                                    );
                                TraceEvents(
                                    TRACE_LEVEL_INFORMATION,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                                    szIpAddress,
                                    usRemotePort
                                    );
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                            usRemotePort = pFlowContext->usRemotePort;
                            bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                            pFlowContext->bUdpQueryClassifyPended = TRUE;
                            pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                            pFlowContext->ulUdpQueryCount++;
                            pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                            pFlowContext->pUdpQuery2BufferList = NULL;
                            pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                            pFlowContext->ulUdpQuery2BufferSize = 0;
                            pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                            pFlowContext->ulUdpQuery2DataOffset = 0;
                            pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                            pFlowContext->ulUdpQuery2PacketOffset = 0;
                            pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                            pFlowContext->ulUdpQuery2DataLength = 0;
                            pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                            pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                            pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                            pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                            pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                            pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                            pFlowContext->enContextState = csUdpWaitReadQuery;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            //ASSERT(FALSE);
                            InsertTailList(
                                &g_stUdpALEAcceptPendedList,
                                &pFlowContext->listEntry
                                );
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitDnsQueryQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfRequestRetrieveOutputMemory(
                                wdfPendedRequest,
                                &wdfOutputMemory
                                );
                            ASSERT(NT_SUCCESS(status));
                            status = WdfMemoryCopyFromBuffer(
                                wdfOutputMemory,
                                0,
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            ASSERT(NT_SUCCESS(status));
                            WdfRequestCompleteWithInformation(
                                wdfPendedRequest,
                                status,
                                sizeof(FLOW_DATA)
                                );
                            WdfObjectDelete(wdfRequestQueue);
                        }
                    }
                    classifyOut->actionType = FWP_ACTION_PERMIT;
                    WdfObjectReleaseLock(wdfDeviceObject);
                    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
                            );
                    }
                    if (!NT_SUCCESS(status))
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                            status
                            );
                    }
                    break;
                }
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQueryDone\"."
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
            FWPS_METADATA_FIELD_REMOTE_SCOPE_ID))
        {
            RtlCopyMemory(
                &pFlowData->stUdpResponceSendParams.remoteScopeId,
                &inMetaValues->remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        else
        {
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams.remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(
            inMetaValues,
            FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
        {
            ASSERT(inMetaValues->controlDataLength > 0);
            pFlowData->stUdpResponceSendParams.controlData = (WSACMSGHDR*) ExAllocatePoolWithTag(
                NonPagedPool,
                inMetaValues->controlDataLength,
                POOL_TAG
                );
            ASSERT(NULL != pFlowData->stUdpResponceSendParams.controlData);
            RtlCopyMemory(
                pFlowData->stUdpResponceSendParams.controlData,
                inMetaValues->controlData,
                inMetaValues->controlDataLength
                );
            pFlowData->stUdpResponceSendParams.controlDataLength = inMetaValues->controlDataLength;
        }
        else
        {
            if (NULL != pFlowData->stUdpResponceSendParams.controlData)
            {
                ExFreePoolWithTag(
                    pFlowData->stUdpResponceSendParams.controlData,
                    POOL_TAG
                    );
            }
            pFlowData->stUdpResponceSendParams.controlData = NULL;
            pFlowData->stUdpResponceSendParams.controlDataLength = 0;
        }
        if (bIPv6)
        {
            pFlowData->stUdpResponceSendParams.remoteAddress = (UCHAR*) &pFlowData->stRemoteAddressV6;
        }
        else
        {
            pFlowData->stUdpResponceSendParams.remoteAddress = (UCHAR*) &pFlowData->nRemoteAddressV4N;
        }
        FwpsReferenceNetBufferList(pNetBufferList, TRUE);
        pFlowData->pUdpResponceBufferList = pNetBufferList;
        pFlowData->ulUdpResponceBufferSize = nDataSize;
        ulUdpDataOffset = ulTransportHeaderSize;
        pFlowData->ulUdpResponceDataOffset = ulUdpDataOffset;
        ulUdpDataLength = nDataSize - ulTransportHeaderSize;
        pFlowData->nUdpResponceDataLength = ulUdpDataLength;
        pFlowData->enUdpResponceCompartmentID = enUdpCompartmentID;
        pFlowData->ulUdpResponceIpHeaderSize = ulIpHeaderSize;
        pFlowData->ulUdpResponceTransportHeaderSize = ulTransportHeaderSize;
        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
        pFlowData->hUdpResponceEndpointHandle = inMetaValues->transportEndpointHandle;
        pFlowData->hUdpInjectEndpointHandle = inMetaValues->transportEndpointHandle;
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        pFlowData->enContextState = csUdpWaitResponce1Pended;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue);
        InsertTailList(&g_stPendedPacketsQueue, &pFlowData->threadListEntry);
        WdfObjectReleaseLock(wdfDeviceObject);
        if (bSignalWorkerThread)
        {
            KeSetEvent(
                &g_oWorkerEvent,
                0,
                FALSE
                );
        }
        break;
    case csUdpWaitResponce2Pended:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        if (!bInbound)
        {
            KeClearEvent(&g_oWorkerEvent);
            if (IsListHeadBad(&g_stPendedPacketsQueue))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Invalid \"g_stPendedPacketsQueue\"!!"
                    );
                InitializeListHead(&g_stPendedPacketsQueue);
            }
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Double send responce #2 to host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            pFlowData->enContextState = csUdpFlowBreak;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // inbound
        if (pFlowData->bUdpQueryClassifyPended)
        {
            pFlowData->bUdpQueryClassifyPended = FALSE;
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query #2 from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(wdfDeviceObject);
            break;
        }
        if ((usRemotePort != pFlowData->usRemotePort)
            && (!IsListEmpty(&g_stUdpAcceptNotifyList)))
        {
            ulInboundCount = 0;
            pListEntry = g_stUdpAcceptNotifyList.Flink;
            pLastLE = g_stUdpAcceptNotifyList.Blink;
            for (;;)
            {
                pNextLE = pListEntry->Flink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                        && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        ulInboundCount++;
                        break;
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        ulInboundCount++;
                        break;
                    }
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pNextLE;
            }
            if (ulInboundCount > 0)
            {
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                pFlowContext->bIPv6 = FALSE;
                pFlowContext->bUdpNotifyQuery = FALSE;
                pFlowContext->enContextState = csWaitQueryStarted;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foAcceptableList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stAcceptableList,
                    &pFlowContext->listEntry
                    );
                ulInboundCount = 0;
                if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
                {
                    pListEntry = g_stUdpALEAcceptPendedList.Flink;
                    pLastLE = g_stUdpALEAcceptPendedList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (ulInboundCount > 0)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        //ASSERT(FALSE);
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
                {
                    pListEntry = g_stUdpInboundList.Flink;
                    pLastLE = g_stUdpInboundList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (1 == ulInboundCount)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                        pFlowContext->pUdpQuery2BufferList = NULL;
                        pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                        pFlowContext->ulUdpQuery2BufferSize = 0;
                        pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                        pFlowContext->ulUdpQuery2DataOffset = 0;
                        pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                        pFlowContext->ulUdpQuery2PacketOffset = 0;
                        pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                        pFlowContext->ulUdpQuery2DataLength = 0;
                        pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                        pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                        pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                        pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                        pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                        pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        //ASSERT(FALSE);
                        InsertTailList(
                            &g_stUdpALEAcceptPendedList,
                            &pFlowContext->listEntry
                            );
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                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
                        );
                }
                if (!NT_SUCCESS(status))
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                        status
                        );
                }
                break;
            }
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        ASSERT(FALSE);
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowData->enContextState = csUdpIllegalInbound;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        break;
    case csUdpPermitQuery2Done:
        if (!bInbound)
        {
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQuery2Done\"."
                    );
            }
            if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
                FWPS_METADATA_FIELD_REMOTE_SCOPE_ID))
            {
                RtlCopyMemory(
                    &pFlowData->stUdpResponce2SendParams.remoteScopeId,
                    &inMetaValues->remoteScopeId,
                    sizeof(SCOPE_ID)
                    );
            }
            else
            {
                RtlZeroMemory(
                    &pFlowData->stUdpResponce2SendParams.remoteScopeId,
                    sizeof(SCOPE_ID)
                    );
            }
            if (FWPS_IS_METADATA_FIELD_PRESENT(
                inMetaValues,
                FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
            {
                ASSERT(inMetaValues->controlDataLength > 0);
                pFlowData->stUdpResponce2SendParams.controlData = (WSACMSGHDR*) ExAllocatePoolWithTag(
                    NonPagedPool,
                    inMetaValues->controlDataLength,
                    POOL_TAG
                    );
                ASSERT(NULL != pFlowData->stUdpResponce2SendParams.controlData);
                RtlCopyMemory(
                    pFlowData->stUdpResponce2SendParams.controlData,
                    inMetaValues->controlData,
                    inMetaValues->controlDataLength
                    );
                pFlowData->stUdpResponce2SendParams.controlDataLength = inMetaValues->controlDataLength;
            }
            else
            {
                if (NULL != pFlowData->stUdpResponce2SendParams.controlData)
                {
                    ExFreePoolWithTag(
                        pFlowData->stUdpResponce2SendParams.controlData,
                        POOL_TAG
                        );
                }
                pFlowData->stUdpResponce2SendParams.controlData = NULL;
                pFlowData->stUdpResponce2SendParams.controlDataLength = 0;
            }
            if (bIPv6)
            {
                pFlowData->stUdpResponce2SendParams.remoteAddress = (UCHAR*) &pFlowData->stRemoteAddressV6;
            }
            else
            {
                pFlowData->stUdpResponce2SendParams.remoteAddress = (UCHAR*) &pFlowData->nRemoteAddressV4N;
            }
            FwpsReferenceNetBufferList(
                pNetBufferList,
                TRUE
                );
            pFlowData->pUdpResponce2BufferList = pNetBufferList;
            pFlowData->ulUdpResponce2BufferSize = nDataSize;
            ulUdpDataOffset = ulTransportHeaderSize;
            pFlowData->ulUdpResponce2DataOffset = ulUdpDataOffset;
            ulUdpDataLength = nDataSize - ulTransportHeaderSize;
            pFlowData->nUdpResponce2DataLength = ulUdpDataLength;
            pFlowData->enUdpResponce2CompartmentID = enUdpCompartmentID;
            pFlowData->ulUdpResponce2IpHeaderSize = ulIpHeaderSize;
            pFlowData->ulUdpResponce2TransportHeaderSize = ulTransportHeaderSize;
            ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
                FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
            pFlowData->hUdpResponce2EndpointHandle = inMetaValues->transportEndpointHandle;
            pFlowData->hUdpInject2EndpointHandle = inMetaValues->transportEndpointHandle;
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            pFlowData->enContextState = csUdpWaitResponce2Pended;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue);
            InsertTailList(&g_stPendedPacketsQueue, &pFlowData->threadListEntry);
            WdfObjectReleaseLock(wdfDeviceObject);
            if (bSignalWorkerThread)
            {
                KeSetEvent(
                    &g_oWorkerEvent,
                    0,
                    FALSE
                    );
            }
            break;
        }
        // inbound
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        if (pFlowData->bUdpQueryClassifyPended)
        {
            pFlowData->bUdpQueryClassifyPended = FALSE;
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query #2 from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(wdfDeviceObject);
            break;
        }
        if ((usRemotePort != pFlowData->usRemotePort)
            && (!IsListEmpty(&g_stUdpAcceptNotifyList)))
        {
            ulInboundCount = 0;
            pListEntry = g_stUdpAcceptNotifyList.Flink;
            pLastLE = g_stUdpAcceptNotifyList.Blink;
            for (;;)
            {
                pNextLE = pListEntry->Flink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                        && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        ulInboundCount++;
                        break;
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        ulInboundCount++;
                        break;
                    }
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pNextLE;
            }
            if (ulInboundCount > 0)
            {
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                pFlowContext->bIPv6 = FALSE;
                pFlowContext->bUdpNotifyQuery = FALSE;
                pFlowContext->enContextState = csWaitQueryStarted;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foAcceptableList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stAcceptableList,
                    &pFlowContext->listEntry
                    );
                ulInboundCount = 0;
                if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
                {
                    pListEntry = g_stUdpALEAcceptPendedList.Flink;
                    pLastLE = g_stUdpALEAcceptPendedList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (ulInboundCount > 0)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        //ASSERT(FALSE);
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
                {
                    pListEntry = g_stUdpInboundList.Flink;
                    pLastLE = g_stUdpInboundList.Blink;
                    for (;;)
                    {
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bUdpQueryClassifyPended)
                        {
                            ulInboundCount++;
                            break;
                        }
                        if (pListEntry == pLastLE)
                        {
                            break;
                        }
                        pListEntry = pListEntry->Flink;
                    }
                    if (1 == ulInboundCount)
                    {
                        bIPv6 = pFlowContext->bIPv6;
                        if (bIPv6)
                        {
                            RtlCopyMemory(
                                &stRemoteAddress,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stRemoteAddress)
                                );
                        }
                        else
                        {
                            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        }
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                        if (bTestIpV4)
                        {
                            stIpAddress.S_un.S_addr = ulRemoteAddressN;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_INFORMATION,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                                szIpAddress,
                                usRemotePort
                                );
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                        usRemotePort = pFlowContext->usRemotePort;
                        bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                        pFlowContext->bUdpQueryClassifyPended = TRUE;
                        pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                        pFlowContext->ulUdpQueryCount++;
                        pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                        pFlowContext->pUdpQuery2BufferList = NULL;
                        pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                        pFlowContext->ulUdpQuery2BufferSize = 0;
                        pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                        pFlowContext->ulUdpQuery2DataOffset = 0;
                        pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                        pFlowContext->ulUdpQuery2PacketOffset = 0;
                        pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                        pFlowContext->ulUdpQuery2DataLength = 0;
                        pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                        pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                        pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                        pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                        pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                        pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                        pFlowContext->enContextState = csUdpWaitReadQuery;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        //ASSERT(FALSE);
                        InsertTailList(
                            &g_stUdpALEAcceptPendedList,
                            &pFlowContext->listEntry
                            );
                        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                        ASSERT(NULL != wdfRequestQueue);
                        pFlowContext->wdfWaitDnsQueryQueue = NULL;
                        status = WdfIoQueueRetrieveNextRequest(
                            wdfRequestQueue,
                            &wdfPendedRequest
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfRequestRetrieveOutputMemory(
                            wdfPendedRequest,
                            &wdfOutputMemory
                            );
                        ASSERT(NT_SUCCESS(status));
                        status = WdfMemoryCopyFromBuffer(
                            wdfOutputMemory,
                            0,
                            pFlowContext,
                            sizeof(FLOW_DATA)
                            );
                        ASSERT(NT_SUCCESS(status));
                        WdfRequestCompleteWithInformation(
                            wdfPendedRequest,
                            status,
                            sizeof(FLOW_DATA)
                            );
                        WdfObjectDelete(wdfRequestQueue);
                    }
                }
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                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
                        );
                }
                if (!NT_SUCCESS(status))
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                        status
                        );
                }
                break;
            }
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        ASSERT(FALSE);
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowData->enContextState = csUdpIllegalInbound;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        break;
    case csUdpFlowDone:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpFlowDone\"."
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! UDP flow is Done"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    case csUdpWaitResponce2:
        if (bInbound)
        {
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2\"."
                );
        }
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    case csUdpWaitPermitQuery:
        if (bInbound)
        {
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            if (pFlowContext->bUdpQueryClassifyPended)
            {
                pFlowContext->bUdpQueryClassifyPended = FALSE;
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query from host %ws; clent.port = %hu;",
                    szIpAddress,
                    pFlowData->usRemotePort
                    );
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                break;
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitPermitQuery\"."
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
            FWPS_METADATA_FIELD_REMOTE_SCOPE_ID))
        {
            RtlCopyMemory(
                &pFlowData->stUdpResponceSendParams.remoteScopeId,
                &inMetaValues->remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        else
        {
            RtlZeroMemory(
                &pFlowData->stUdpResponceSendParams.remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(
            inMetaValues,
            FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
        {
            ASSERT(inMetaValues->controlDataLength > 0);
            pFlowData->stUdpResponceSendParams.controlData = (WSACMSGHDR*) ExAllocatePoolWithTag(
                NonPagedPool,
                inMetaValues->controlDataLength,
                POOL_TAG
                );
            ASSERT(NULL != pFlowData->stUdpResponceSendParams.controlData);
            RtlCopyMemory(
                pFlowData->stUdpResponceSendParams.controlData,
                inMetaValues->controlData,
                inMetaValues->controlDataLength
                );
            pFlowData->stUdpResponceSendParams.controlDataLength = inMetaValues->controlDataLength;
        }
        else
        {
            if (NULL != pFlowData->stUdpResponceSendParams.controlData)
            {
                ExFreePoolWithTag(
                    pFlowData->stUdpResponceSendParams.controlData,
                    POOL_TAG
                    );
            }
            pFlowData->stUdpResponceSendParams.controlData = NULL;
            pFlowData->stUdpResponceSendParams.controlDataLength = 0;
        }
        if (bIPv6)
        {
            pFlowData->stUdpResponceSendParams.remoteAddress = (UCHAR*) &pFlowData->stRemoteAddressV6;
        }
        else
        {
            pFlowData->stUdpResponceSendParams.remoteAddress = (UCHAR*) &pFlowData->nRemoteAddressV4N;
        }
        FwpsReferenceNetBufferList(pNetBufferList, TRUE);
        pFlowData->pUdpResponceBufferList = pNetBufferList;
        pFlowData->ulUdpResponceBufferSize = nDataSize;
        ulUdpDataOffset = ulTransportHeaderSize;
        pFlowData->ulUdpResponceDataOffset = ulUdpDataOffset;
        ulUdpDataLength = nDataSize - ulTransportHeaderSize;
        pFlowData->nUdpResponceDataLength = ulUdpDataLength;
        pFlowData->enUdpResponceCompartmentID = enUdpCompartmentID;
        pFlowData->ulUdpResponceIpHeaderSize = ulIpHeaderSize;
        pFlowData->ulUdpResponceTransportHeaderSize = ulTransportHeaderSize;
        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
        pFlowData->hUdpResponceEndpointHandle = inMetaValues->transportEndpointHandle;
        pFlowData->hUdpInjectEndpointHandle = inMetaValues->transportEndpointHandle;
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        pFlowData->enContextState = csUdpWaitResponce1Pended;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue);
        InsertTailList(&g_stPendedPacketsQueue, &pFlowData->threadListEntry);
        WdfObjectReleaseLock(wdfDeviceObject);
        if (bSignalWorkerThread)
        {
            KeSetEvent(
                &g_oWorkerEvent,
                0,
                FALSE
                );
        }
        break;
    case csUdpWaitPermitQuery2:
        if (bInbound)
        {
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            if (pFlowContext->bUdpQueryClassifyPended)
            {
                pFlowContext->bUdpQueryClassifyPended = FALSE;
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Receive Pended UDP-Query from host %ws; clent.port = %hu;",
                    szIpAddress,
                    pFlowData->usRemotePort
                    );
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_PERMIT;
                WdfObjectReleaseLock(wdfDeviceObject);
                break;
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Unexpect Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            ulInboundCount = 0;
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
            {
                pListEntry = g_stUdpInboundList.Flink;
                pLastLE = g_stUdpInboundList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (1 == ulInboundCount)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        RtlCopyMemory(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6,
                            sizeof(stRemoteAddress)
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                    pFlowContext->pUdpQuery2BufferList = NULL;
                    pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                    pFlowContext->ulUdpQuery2BufferSize = 0;
                    pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                    pFlowContext->ulUdpQuery2DataOffset = 0;
                    pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                    pFlowContext->ulUdpQuery2PacketOffset = 0;
                    pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                    pFlowContext->ulUdpQuery2DataLength = 0;
                    pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                    pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                    pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                    pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                    pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                    pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    //ASSERT(FALSE);
                    InsertTailList(
                        &g_stUdpALEAcceptPendedList,
                        &pFlowContext->listEntry
                        );
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            pFlowData->enContextState = csUdpIllegalInbound;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(wdfDeviceObject);
            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
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            break;
        }
        // outbound
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitPermitQuery2\"."
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
            FWPS_METADATA_FIELD_REMOTE_SCOPE_ID))
        {
            RtlCopyMemory(
                &pFlowData->stUdpResponce2SendParams.remoteScopeId,
                &inMetaValues->remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        else
        {
            RtlZeroMemory(
                &pFlowData->stUdpResponce2SendParams.remoteScopeId,
                sizeof(SCOPE_ID)
                );
        }
        if (FWPS_IS_METADATA_FIELD_PRESENT(
            inMetaValues,
            FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
        {
            ASSERT(inMetaValues->controlDataLength > 0);
            pFlowData->stUdpResponce2SendParams.controlData = (WSACMSGHDR*) ExAllocatePoolWithTag(
                NonPagedPool,
                inMetaValues->controlDataLength,
                POOL_TAG
                );
            ASSERT(NULL != pFlowData->stUdpResponce2SendParams.controlData);
            RtlCopyMemory(
                pFlowData->stUdpResponce2SendParams.controlData,
                inMetaValues->controlData,
                inMetaValues->controlDataLength
                );
            pFlowData->stUdpResponce2SendParams.controlDataLength = inMetaValues->controlDataLength;
        }
        else
        {
            if (NULL != pFlowData->stUdpResponce2SendParams.controlData)
            {
                ExFreePoolWithTag(
                    pFlowData->stUdpResponce2SendParams.controlData,
                    POOL_TAG
                    );
            }
            pFlowData->stUdpResponce2SendParams.controlData = NULL;
            pFlowData->stUdpResponce2SendParams.controlDataLength = 0;
        }
        if (bIPv6)
        {
            pFlowData->stUdpResponce2SendParams.remoteAddress = (UCHAR*) &pFlowData->stRemoteAddressV6;
        }
        else
        {
            pFlowData->stUdpResponce2SendParams.remoteAddress = (UCHAR*) &pFlowData->nRemoteAddressV4N;
        }
        FwpsReferenceNetBufferList(
            pNetBufferList,
            TRUE
            );
        pFlowData->pUdpResponce2BufferList = pNetBufferList;
        pFlowData->ulUdpResponce2BufferSize = nDataSize;
        ulUdpDataOffset = ulTransportHeaderSize;
        pFlowData->ulUdpResponce2DataOffset = ulUdpDataOffset;
        ulUdpDataLength = nDataSize - ulTransportHeaderSize;
        pFlowData->nUdpResponce2DataLength = ulUdpDataLength;
        pFlowData->enUdpResponce2CompartmentID = enUdpCompartmentID;
        pFlowData->ulUdpResponce2IpHeaderSize = ulIpHeaderSize;
        pFlowData->ulUdpResponce2TransportHeaderSize = ulTransportHeaderSize;
        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
            FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
        pFlowData->hUdpResponce2EndpointHandle = inMetaValues->transportEndpointHandle;
        pFlowData->hUdpInject2EndpointHandle = inMetaValues->transportEndpointHandle;
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        pFlowData->enContextState = csUdpWaitResponce2Pended;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        bSignalWorkerThread = IsListEmpty(&g_stPendedPacketsQueue);
        InsertTailList(&g_stPendedPacketsQueue, &pFlowData->threadListEntry);
        WdfObjectReleaseLock(wdfDeviceObject);
        if (bSignalWorkerThread)
        {
            KeSetEvent(
                &g_oWorkerEvent,
                0,
                FALSE
                );
        }
        break;
    case csUdpWaitReadQuery:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Unexpect UDP-Message in state =\"csUdpWaitReadQuery\" from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    case csUdpWaitReadQuery2:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Unexpect UDP-Message in state =\"csUdpWaitReadQuery2\" from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    case csUdpFlowBreak:
        if (pFlowData->bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Unexpect UDP-Message in state =\"csUdpFlowBreak\" from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowData->usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine = %u",
            pFlowData->enContextState
            );
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        ASSERT(FALSE);
        WdfObjectReleaseLock(wdfDeviceObject);
        break;
    }
}

void
dnsfirewallWorker(
__in PVOID  StartContext
)
{
    PFLOW_DATA          pFlowContext;
    PLIST_ENTRY         pListEntry;
    NTSTATUS            status = STATUS_SUCCESS;
    WDFFILEOBJECT       wdfFlowFileObject;
    PNET_BUFFER_LIST    pNetBufferList;
    COMPARTMENT_ID      enCompartmentID;
    PNET_BUFFER_LIST    pCloneBufferList;
    BOOLEAN             bEmpty;
    BOOLEAN             bTestIpV4 = FALSE;
    BOOLEAN             bIPv6;
    UINT32              ulRemoteAddress = 0, ulRemoteAddressN = 0;
    IN_ADDR             stIpAddress;
    WCHAR               szIpAddress[128];
    LPWSTR              pAddressEnd;
    UINT16              usRemotePort;
    IN6_ADDR            stIp6Address;
    IPPROTO             enIpProto;
    StartContext;
    for (;;)
    {
        KeWaitForSingleObject(
            &g_oWorkerEvent,
            Executive,
            KernelMode,
            FALSE,
            NULL
            );
        if (g_bDriverUnload)
        {
            break;
        }
        WdfObjectAcquireLock(g_wdfControlDevice);
        if (IsListEmpty(&g_stPendedPacketsQueue))
        {
            KeClearEvent(&g_oWorkerEvent);
            WdfObjectReleaseLock(g_wdfControlDevice);
            continue;
        }
        if (IsListHeadBad(&g_stPendedPacketsQueue))
        {
            KeClearEvent(&g_oWorkerEvent);
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Invalid \"g_stPendedPacketsQueue\"!!"
                );
            InitializeListHead(&g_stPendedPacketsQueue);
            WdfObjectReleaseLock(g_wdfControlDevice);
            continue;
        }
        pListEntry = RemoveHeadList(&g_stPendedPacketsQueue);
        pFlowContext = CONTAINING_RECORD(
            pListEntry,
            FLOW_DATA,
            threadListEntry
            );
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        bIPv6 = pFlowContext->bIPv6;
        usRemotePort = pFlowContext->usRemotePort;
        enIpProto = pFlowContext->enIpProto;
        if (!bIPv6)
        {
            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
            ulRemoteAddressN = pFlowContext->nRemoteAddressV4N;
            bTestIpV4 = ((IPPROTO_UDP == enIpProto) && (c_ulTestIpV4 == ulRemoteAddress));
            if (bTestIpV4)
            {
                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                    szIpAddress,
                    usRemotePort
                    );
            }
        }
        switch (pFlowContext->enContextState)
        {
        case csUdpPermitQueryPended:
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQueryPended\"."
                    );
            }
            pFlowContext->enContextState = csUdpWaitPermitQuery;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pUdpQueryCloneBufferList;
            enCompartmentID = pFlowContext->enUdpQueryCompartmentID;
            if (pFlowContext->bUdpQueryClassifyPended)
            {
                if (bTestIpV4)
                {
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on (pFlowContext->bUdpQueryClassifyPended)."
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                if (NULL != pFlowContext->hAleAuthRecvAcceptContext)
                {
                    FwpsCompleteOperation(
                        pFlowContext->hAleAuthRecvAcceptContext,
                        pNetBufferList
                        );
                }
                pFlowContext->enFlowDataOwner = foUdpALEFlowEstablishList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                InsertTailList(
                    &g_stUdpALEFlowEstablishList,
                    &pFlowContext->listEntry
                    );
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsInjectTransportReceiveAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    NULL,
                    0,
                    AF_INET6,
                    enCompartmentID,
                    pFlowContext->interfaceIndex,
                    pFlowContext->subInterfaceIndex,
                    pNetBufferList,
                    clonedDatagramDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsInjectTransportReceiveAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    NULL,
                    0,
                    AF_INET,
                    enCompartmentID,
                    pFlowContext->interfaceIndex,
                    pFlowContext->subInterfaceIndex,
                    pNetBufferList,
                    clonedDatagramDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsInjectTransportReceiveAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csUdpPermitQuery2Pended:
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpPermitQuery2Pended\"."
                    );
            }
            pFlowContext->enContextState = csUdpWaitPermitQuery2;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pUdpQuery2CloneBufferList;
            enCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsInjectTransportReceiveAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    NULL,
                    0,
                    AF_INET6,
                    enCompartmentID,
                    pFlowContext->interfaceIndex,
                    pFlowContext->subInterfaceIndex,
                    pNetBufferList,
                    clonedDatagramDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsInjectTransportReceiveAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    NULL,
                    0,
                    AF_INET,
                    enCompartmentID,
                    pFlowContext->interfaceIndex,
                    pFlowContext->subInterfaceIndex,
                    pNetBufferList,
                    clonedDatagramDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsInjectTransportReceiveAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csTcpPermitQueryPended:
            pFlowContext->enContextState = csTcpWaitPermitQuery;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pTcpQueryBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpQueryFlowID,
                    g_nStreamIdV6,
                    FWPS_LAYER_STREAM_V6,
                    FWPS_STREAM_FLAG_RECEIVE,
                    pNetBufferList,
                    pFlowContext->nTcpQueryLength,
                    clonedStreamDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpQueryFlowID,
                    g_nStreamIdV4,
                    FWPS_LAYER_STREAM_V4,
                    FWPS_STREAM_FLAG_RECEIVE,
                    pNetBufferList,
                    pFlowContext->nTcpQueryLength,
                    clonedStreamDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsStreamInjectAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csTcpReplaceQueryPended:
            pFlowContext->enContextState = csTcpWaitReplaceQueryDone;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pTcpQueryInjectBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpQueryFlowID,
                    g_nStreamIdV6,
                    FWPS_LAYER_STREAM_V6,
                    FWPS_STREAM_FLAG_RECEIVE,
                    pNetBufferList,
                    pFlowContext->nTcpQueryInjectDataSize,
                    allocatedStreamDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpQueryFlowID,
                    g_nStreamIdV4,
                    FWPS_LAYER_STREAM_V4,
                    FWPS_STREAM_FLAG_RECEIVE,
                    pNetBufferList,
                    pFlowContext->nTcpQueryInjectDataSize,
                    allocatedStreamDnsQueryCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsStreamInjectAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csTcpPermitResponcePended:
            pFlowContext->enContextState = csTcpWaitPermitResponce;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pTcpResponceBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpResponceFlowID,
                    g_nStreamIdV6,
                    FWPS_LAYER_STREAM_V6,
                    FWPS_STREAM_FLAG_SEND,
                    pNetBufferList,
                    pFlowContext->nTcpResponceLength,
                    clonedStreamDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpResponceFlowID,
                    g_nStreamIdV4,
                    FWPS_LAYER_STREAM_V4,
                    FWPS_STREAM_FLAG_SEND,
                    pNetBufferList,
                    pFlowContext->nTcpResponceLength,
                    clonedStreamDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsStreamInjectAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csTcpReplaceResponcePended:
            pFlowContext->enContextState = csTcpWaitReplaceResponceDone;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pTcpResponceInjectBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpResponceFlowID,
                    g_nStreamIdV6,
                    FWPS_LAYER_STREAM_V6,
                    FWPS_STREAM_FLAG_SEND,
                    pNetBufferList,
                    pFlowContext->nTcpResponceInjectDataSize,
                    allocatedStreamDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsStreamInjectAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext,
                    0,
                    pFlowContext->hTcpResponceFlowID,
                    g_nStreamIdV4,
                    FWPS_LAYER_STREAM_V4,
                    FWPS_STREAM_FLAG_SEND,
                    pNetBufferList,
                    pFlowContext->nTcpResponceInjectDataSize,
                    allocatedStreamDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsStreamInjectAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csUdpWaitResponce1Pended:
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce1Pended\"."
                    );
            }
            pNetBufferList = pFlowContext->pUdpResponceBufferList;
            //
            // Note that the clone will inherit the original net buffer list's offset.
            //
            status = FwpsAllocateCloneNetBufferList(
                pNetBufferList,
                g_hNetBufferListPool,
                NULL,
                0,
                &pCloneBufferList
                );
            ASSERT(NT_SUCCESS(status));
            pFlowContext->pUdpResponceCloneBufferList = pCloneBufferList;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
            pFlowContext->pUdpResponceBufferList = NULL;
            pFlowContext->enContextState = csUdpWaitResponce1;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pUdpResponceCloneBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsInjectTransportSendAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext, // 
                    pFlowContext->hUdpResponceEndpointHandle,
                    0,
                    &pFlowContext->stUdpResponceSendParams,
                    AF_INET6,
                    pFlowContext->enUdpResponceCompartmentID,
                    pNetBufferList,
                    clonedDatagramDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsInjectTransportSendAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext, // 
                    pFlowContext->hUdpResponceEndpointHandle,
                    0,
                    &pFlowContext->stUdpResponceSendParams,
                    AF_INET,
                    pFlowContext->enUdpResponceCompartmentID,
                    pNetBufferList,
                    clonedDatagramDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsInjectTransportSendAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        case csUdpWaitResponce2Pended:
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2Pended\"."
                    );
            }
            pNetBufferList = pFlowContext->pUdpResponce2BufferList;
            //
            // Note that the clone will inherit the original net buffer list's offset.
            //
            status = FwpsAllocateCloneNetBufferList(
                pNetBufferList,
                g_hNetBufferListPool,
                NULL,
                0,
                &pCloneBufferList
                );
            ASSERT(NT_SUCCESS(status));
            pFlowContext->pUdpResponce2CloneBufferList = pCloneBufferList;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
            pFlowContext->pUdpResponce2BufferList = NULL;
            pFlowContext->enContextState = csUdpWaitResponce2;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pNetBufferList = pFlowContext->pUdpResponce2CloneBufferList;
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsInjectTransportSendAsync(
                    g_hInjectionHandleV6,
                    (HANDLE) pFlowContext, // 
                    pFlowContext->hUdpResponce2EndpointHandle,
                    0,
                    &pFlowContext->stUdpResponce2SendParams,
                    AF_INET6,
                    pFlowContext->enUdpResponce2CompartmentID,
                    pNetBufferList,
                    clonedDatagramDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            else
            {
                status = FwpsInjectTransportSendAsync(
                    g_hInjectionHandleV4,
                    (HANDLE) pFlowContext, // 
                    pFlowContext->hUdpResponce2EndpointHandle,
                    0,
                    &pFlowContext->stUdpResponce2SendParams,
                    AF_INET,
                    pFlowContext->enUdpResponce2CompartmentID,
                    pNetBufferList,
                    clonedDatagramDnsResponceCompletionFn,
                    (HANDLE) pFlowContext
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"FwpsInjectTransportSendAsync\" failed with status = %!STATUS!;",
                    status
                    );
            }
            break;
        default:
            if (bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowContext->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine = %u!! Host %ws; clent.port = %hu;",
                pFlowContext->enContextState,
                szIpAddress,
                usRemotePort
                );
            WdfObjectReleaseLock(g_wdfControlDevice);
            break;
        }
    }
    ASSERT(g_bDriverUnload);
    WdfObjectAcquireLock(g_wdfControlDevice);
    while (!IsListEmpty(&g_stPendedPacketsQueue))
    {
        if (!IsListEmpty(&g_stPendedPacketsQueue))
        {
            pListEntry = RemoveTailList(&g_stPendedPacketsQueue);
        }
    }
    KeSetEvent(
        &g_oWorkerDoneEvent,
        0,
        FALSE
        );
    WdfObjectReleaseLock(g_wdfControlDevice);
    PsTerminateSystemThread(STATUS_SUCCESS);
    ObDereferenceObject(g_pWorkerThreadObj);
    g_pWorkerThreadObj = NULL;
}

void FilterDataCleanup(
    PADDRESSES_DESCRIPTOR pDeviceAddressesDescriptor
    )
{
    NTSTATUS            status = STATUS_SUCCESS;
    PFLOW_DATA          pFlowContext = NULL;
    PLIST_ENTRY         pFlowContextEntry;
    WDFQUEUE            wdfRequestQueue = NULL;
    WDFREQUEST          wdfPendedRequest = NULL;
    PNET_BUFFER_LIST    pNetBufferList;
    while (!IsListEmpty(&g_stFlowedFileList))
    {
        pFlowContextEntry = g_stFlowedFileList.Blink;
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        ASSERT(0 != pFlowContext->flowHandle);
        pFlowContext->enContextState = csFlowDeleted;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
#pragma warning(suppress: 26110)
        WdfObjectReleaseLock(g_wdfControlDevice);
        if (IPPROTO_UDP == pFlowContext->enIpProto)
        {
            if (pFlowContext->bIPv6)
            {
                status = FwpsFlowRemoveContext(
                    pFlowContext->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V6,
                    g_nDatagramIdV6
                    );
            }
            else
            {
                status = FwpsFlowRemoveContext(
                    pFlowContext->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V4,
                    g_nDatagramIdV4
                    );
            }
        }
        else
        {
            if (pFlowContext->bIPv6)
            {
                status = FwpsFlowRemoveContext(
                    pFlowContext->flowHandle,
                    FWPS_LAYER_STREAM_V6,
                    g_nStreamIdV6
                    );
            }
            else
            {
                status = FwpsFlowRemoveContext(
                    pFlowContext->flowHandle,
                    FWPS_LAYER_STREAM_V4,
                    g_nStreamIdV4
                    );
            }
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        WdfObjectAcquireLock(g_wdfControlDevice);
    }
    while (!IsListEmpty(&g_stUdpALEFlowEstablishList))
    {
        pFlowContextEntry = RemoveTailList(&g_stUdpALEFlowEstablishList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        pNetBufferList = pFlowContext->pUdpQueryCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowContext->pUdpQueryCloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        if (csUdpPermitQueryPended == pFlowContext->enContextState)
        {
            if (IsListEntryInList(&pFlowContext->threadListEntry, &g_stPendedPacketsQueue))
            {
                RtlZeroMemory(&pFlowContext->threadListEntry, sizeof(pFlowContext->threadListEntry));
                InitializeListHead(&g_stPendedPacketsQueue);
            }
        }
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stUdpALEAcceptPendedList))
    {
        pFlowContextEntry = RemoveTailList(&g_stUdpALEAcceptPendedList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        pNetBufferList = pFlowContext->pUdpQueryCloneBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowContext->pUdpQueryCloneBufferList = NULL;
            FwpsFreeCloneNetBufferList(
                pNetBufferList,
                0
                );
        }
        pNetBufferList = pFlowContext->pUdpQueryBufferList;
        if (NULL != pNetBufferList)
        {
            pFlowContext->pUdpQueryBufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        if (csUdpPermitQueryPended == pFlowContext->enContextState)
        {
            if (IsListEntryInList(&pFlowContext->threadListEntry, &g_stPendedPacketsQueue))
            {
                RtlZeroMemory(&pFlowContext->threadListEntry, sizeof(pFlowContext->threadListEntry));
                InitializeListHead(&g_stPendedPacketsQueue);
            }
        }
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stUdpAcceptNotifyList))
    {
        pFlowContextEntry = RemoveTailList(&g_stUdpAcceptNotifyList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stUdpALEAcceptRecvList))
    {
        pFlowContextEntry = RemoveTailList(&g_stUdpALEAcceptRecvList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stUdpInboundList))
    {
        pFlowContextEntry = RemoveTailList(&g_stUdpInboundList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        pNetBufferList = pFlowContext->pUdpQuery2BufferList;
        if (NULL != pNetBufferList)
        {
            pFlowContext->pUdpQuery2BufferList = NULL;
            FwpsDereferenceNetBufferList(
                pNetBufferList,
                FALSE
                );
        }
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stAcceptableList))
    {
        pFlowContextEntry = RemoveTailList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stWaitForSetFilterFileList))
    {
        pFlowContextEntry = RemoveTailList(&g_stWaitForSetFilterFileList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stWaitForQuery2FileList))
    {
        pFlowContextEntry = RemoveTailList(&g_stWaitForQuery2FileList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    while (!IsListEmpty(&g_stWaitForDoneFileList))
    {
        pFlowContextEntry = RemoveTailList(&g_stWaitForDoneFileList);
        pFlowContext = CONTAINING_RECORD(pFlowContextEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
        if (NULL != wdfRequestQueue)
        {
            pFlowContext->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_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                    status
                    );
            }
            WdfObjectDelete(wdfRequestQueue);
        }
        pFlowContext->enContextState = csNotRun;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    }
    g_bFiltersChangeInProgress = FALSE;
    RtlZeroMemory(
        &g_stFirewallConfig,
        sizeof(g_stFirewallConfig)
        );
    InitializeListHead(&g_stFreeFileList);
    InitializeListHead(&g_stWaitForDoneFileList);
    InitializeListHead(&g_stWaitForQuery2FileList);
    InitializeListHead(&g_stWaitForSetFilterFileList);
    InitializeListHead(&g_stAcceptableList);
    InitializeListHead(&g_stUdpInboundList);
    InitializeListHead(&g_stUdpALEAcceptRecvList);
    InitializeListHead(&g_stUdpAcceptNotifyList);
    InitializeListHead(&g_stUdpALEAcceptPendedList);
    InitializeListHead(&g_stUdpALEFlowEstablishList);
    InitializeListHead(&g_stFlowedFileList);
    InitializeListHead(&g_stPendedPacketsQueue);
    if (NULL != g_wdfWaitRestartQueue)
    {
        WdfObjectDelete(g_wdfWaitRestartQueue);
        g_wdfWaitRestartQueue = NULL;
    }
    if (NULL != pDeviceAddressesDescriptor->m_pDataArray)
    {
        ExFreePoolWithTag(
            pDeviceAddressesDescriptor->m_pDataArray,
            POOL_TAG
            );
    }
    RtlZeroMemory(
        pDeviceAddressesDescriptor,
        sizeof(ADDRESSES_DESCRIPTOR)
        );
}

void NTAPI clonedDatagramDnsQueryCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT   wdfFlowFileObject = NULL;
    PFLOW_DATA      pFlowData;
    WDFREQUEST      wdfPendedRequest;
    NTSTATUS        status = STATUS_SUCCESS;
    WDFDEVICE       wdfDeviceObject;
    WDFQUEUE        wdfRequestQueue = NULL;
    BOOLEAN         bTestIpV4 = FALSE;
    BOOLEAN         bIPv6;
    UINT32          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    IN_ADDR         stIpAddress;
    WCHAR           szIpAddress[128];
    LPWSTR          pAddressEnd;
    UINT16          usRemotePort;
    IN6_ADDR        stIp6Address;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    if ((csNotRun == pFlowData->enContextState) || (csFlowDeleted == pFlowData->enContextState))
    {
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    ASSERT(pFlowData == pFlowData->pThis);
    FwpsFreeCloneNetBufferList(
        netBufferList,
        0
        );
    bIPv6 = pFlowData->bIPv6;
    usRemotePort = pFlowData->usRemotePort;
    if (!bIPv6)
    {
        ulRemoteAddress = pFlowData->nRemoteAddressV4;
        ulRemoteAddressN = pFlowData->nRemoteAddressV4N;
        bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
        if (bTestIpV4)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
        }
    }
    switch (pFlowData->enContextState)
    {
    case csUdpWaitResponce1:
        ASSERT(pFlowData->pUdpQueryCloneBufferList == netBufferList);
        pFlowData->pUdpQueryCloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQueryPermitQueue = NULL;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce1\"."
                );
        }
        break;
    case csUdpWaitResponce1Pended:
        ASSERT(pFlowData->pUdpQueryCloneBufferList == netBufferList);
        pFlowData->pUdpQueryCloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQueryPermitQueue = NULL;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce1Pended\"."
                );
        }
        break;
    case csUdpWaitPermitQuery:
        ASSERT(pFlowData->pUdpQueryCloneBufferList == netBufferList);
        pFlowData->pUdpQueryCloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQueryPermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQueryPermitQueue = NULL;
        pFlowData->enContextState = csUdpPermitQueryDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitPermitQuery\"."
                );
        }
        break;
    case csUdpWaitResponce2:
        ASSERT(pFlowData->pUdpQuery2CloneBufferList == netBufferList);
        pFlowData->pUdpQuery2CloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQuery2PermitQueue = NULL;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2\"."
                );
        }
        break;
    case csUdpWaitResponce2Pended:
        ASSERT(pFlowData->pUdpQuery2CloneBufferList == netBufferList);
        pFlowData->pUdpQuery2CloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQuery2PermitQueue = NULL;
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitResponce2Pended\"."
                );
        }
        break;
    case csUdpWaitPermitQuery2:
        ASSERT(pFlowData->pUdpQuery2CloneBufferList == netBufferList);
        pFlowData->pUdpQuery2CloneBufferList = NULL;
        wdfRequestQueue = pFlowData->wdfUdpQuery2PermitQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowData->wdfUdpQuery2PermitQueue = NULL;
        pFlowData->enContextState = csUdpPermitQuery2Done;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Elaborated on state \"csUdpWaitPermitQuery2\"."
                );
        }
        break;
    default:
        if (bIPv6)
        {
            RtlCopyMemory(
                &stIp6Address,
                &pFlowData->stRemoteAddressV6,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
        }
        else
        {
            stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine = %u!! Host %ws; clent.port = %hu;",
            pFlowData->enContextState,
            szIpAddress,
            usRemotePort
            );
        break;
    }
    if (NULL != wdfRequestQueue)
    {
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(UDP_QUERY_APPROVAL)
            );
        WdfObjectDelete(wdfRequestQueue);
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void GetStreamData(
    NET_BUFFER_LIST* pNetBufferList,
    BYTE* pDataBuffer,
    UINT32 nDataBufferLength,
    UINT32* pByteCopied
    )
{
    NET_BUFFER_LIST*    pCurrentNetBufferList = pNetBufferList;
    NET_BUFFER_LIST*    pNextNetBufferList;
    NET_BUFFER*         pCurrentNetBuffer;
    NET_BUFFER*         pNextNetBuffer;
    BYTE*               pCurrentDataPointer = pDataBuffer;
    BYTE*               pNbDataPointer;
    UINT32              nCurrentBufferLength, nCurrentDataLength = 0;
    BOOLEAN             bBufferDone = FALSE;
    while (NULL != pCurrentNetBufferList)
    {
        pNextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pCurrentNetBufferList);
        pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList);
        while (NULL != pCurrentNetBuffer)
        {
            pNextNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer);
            nCurrentBufferLength = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer);
            nCurrentDataLength += nCurrentBufferLength;
            if (nCurrentDataLength > nDataBufferLength)
            {
                bBufferDone = TRUE;
                nCurrentBufferLength -= nCurrentDataLength - nDataBufferLength;
            }
            if (nCurrentBufferLength > 0)
            {
                pNbDataPointer = (BYTE*) NdisGetDataBuffer(
                    pCurrentNetBuffer,
                    nCurrentBufferLength,
                    pCurrentDataPointer,
                    1,
                    0
                    );
                ASSERT(NULL != pNbDataPointer);
                if (pNbDataPointer != pCurrentDataPointer)
                {
#pragma warning(suppress: 6387)
                    RtlCopyMemory(
                        pCurrentDataPointer,
                        pNbDataPointer,
                        nCurrentBufferLength
                        );
                }
                pCurrentDataPointer += nCurrentBufferLength;
            }
            if (bBufferDone)
            {
                *pByteCopied = nDataBufferLength;
                return;
            }
            pCurrentNetBuffer = pNextNetBuffer;
        }
        pCurrentNetBufferList = pNextNetBufferList;
    }
    *pByteCopied = nCurrentDataLength;
}

void NTAPI clonedStreamDnsQueryCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT   wdfFlowFileObject;
    PFLOW_DATA      pFlowData;
    WDFREQUEST      wdfPendedRequest;
    NTSTATUS        status = STATUS_SUCCESS;
    WDFDEVICE       wdfDeviceObject;
    WDFQUEUE        wdfRequestQueue;
    int             i = 0;
    UINT32          ulInboundCount = 0;
    PLIST_ENTRY     pListEntry, pLastLE;
    PFLOW_DATA      pFlowContext = NULL;
    BOOLEAN         bIPv6;
    IN6_ADDR        stRemoteAddress;
    UINT32          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    UINT16          usRemotePort;
    BOOLEAN         bTestIpV4;
    IN_ADDR         stIpAddress;
    WCHAR           szIpAddress[128];
    LPWSTR          pAddressEnd;
    WDFMEMORY       wdfOutputMemory = NULL;
    BOOLEAN         bEmpty;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    if (csFlowDeleted == pFlowData->enContextState)
    {
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (csFlowDeleted == pFlowData->enContextState)"
            );
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    ASSERT(pFlowData == pFlowData->pThis);
    if (NULL != NET_BUFFER_LIST_NEXT_NBL(netBufferList))
    {
        FwpsFreeCloneNetBufferList(
            netBufferList,
            0
            );
        //push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    else
    {
        FwpsFreeCloneNetBufferList(
            netBufferList,
            0
            );
    }
    pFlowData->pTcpQueryBufferList = NULL;
    pFlowData->hTcpQueryFlowID = 0;
    wdfRequestQueue = pFlowData->wdfTcpQueryPermitQueue;
    if (NULL != wdfRequestQueue)
    {
        pFlowData->wdfTcpQueryPermitQueue = NULL;
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(TCP_QUERY_APPROVAL)
            );
        WdfObjectDelete(wdfRequestQueue);
    }
    switch (pFlowData->arContextStateStack[i])
    {
    case csTcpWaitPermitQuery:
    case csTcpPermitQueryDone:
        pFlowData->enContextState = csTcpPermitQueryDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpWaitQueryInjectDone:
        pFlowData->enContextState = csTcpWaitReadResponce;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csDnsError:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csDnsError\""
            );
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpResponceMoreData02:
        pFlowData->enContextState = csTcpResponceMoreData01;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpClientDisconnect:
    case csTcpServerDisconnect:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine"
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI allocatedStreamDnsQueryCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT   wdfFlowFileObject;
    PFLOW_DATA      pFlowData;
    WDFREQUEST      wdfPendedRequest;
    NTSTATUS        status = STATUS_SUCCESS;
    PMDL            _pMdl;
    ULONG_PTR       Information;
    WDFDEVICE       wdfDeviceObject;
    WDFQUEUE        wdfRequestQueue;
    int             i = 0;
    UINT32          ulInboundCount = 0;
    PLIST_ENTRY     pListEntry, pLastLE;
    PFLOW_DATA      pFlowContext = NULL;
    BOOLEAN         bIPv6;
    IN6_ADDR        stRemoteAddress;
    UINT32          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    UINT16          usRemotePort;
    BOOLEAN         bTestIpV4;
    IN_ADDR         stIpAddress;
    WCHAR           szIpAddress[128];
    LPWSTR          pAddressEnd;
    WDFMEMORY       wdfOutputMemory = NULL;
    BOOLEAN         bEmpty;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    if (csFlowDeleted == pFlowData->enContextState)
    {
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    ASSERT(pFlowData == pFlowData->pThis);
    ASSERT(pFlowData->pTcpQueryInjectBufferList == netBufferList);
    FwpsFreeNetBufferList(
        netBufferList
        );
    pFlowData->pTcpQueryInjectBufferList = NULL;
    _pMdl = pFlowData->pTcpQueryMdl;
    ASSERT(NULL != _pMdl);
    IoFreeMdl(_pMdl);
    ExFreePoolWithTag(
        _pMdl->MappedSystemVa,
        POOL_TAG
        );
    pFlowData->pTcpQueryMdl = NULL;
    wdfRequestQueue = pFlowData->wdfTcpQueryInjectQueue;
    pFlowData->wdfTcpQueryInjectQueue = NULL;
    if (NULL != wdfRequestQueue)
    {
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        Information = pFlowData->nTcpQueryInjectDataSize;
        pFlowData->nTcpQueryInjectDataSize = 0;
        ASSERT(0 != Information);
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            Information
            );
        WdfObjectDelete(wdfRequestQueue);
    }
    switch (pFlowData->arContextStateStack[i])
    {
    case csTcpWaitReplaceQueryDone:
        pFlowData->enContextState = csTcpReplaceQueryDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpWaitQueryInjectDone:
        pFlowData->enContextState = csTcpWaitReadResponce;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csDnsError:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! State of the State machine is \"csDnsError\""
            );
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpResponceMoreData02:
        pFlowData->enContextState = csTcpResponceMoreData01;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpClientDisconnect:
    case csTcpServerDisconnect:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine"
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI clonedStreamDnsResponceCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT   wdfFlowFileObject;
    PFLOW_DATA      pFlowData;
    WDFREQUEST      wdfPendedRequest;
    NTSTATUS        status = STATUS_SUCCESS;
    BOOLEAN         bInbound;
    WDFDEVICE       wdfDeviceObject;
    WDFQUEUE        wdfRequestQueue;
    int             i = 0;
    UINT32          ulInboundCount = 0;
    PLIST_ENTRY     pListEntry, pLastLE;
    PFLOW_DATA      pFlowContext = NULL;
    BOOLEAN         bIPv6;
    IN6_ADDR        stRemoteAddress;
    UINT32          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    UINT16          usRemotePort;
    BOOLEAN         bTestIpV4;
    IN_ADDR         stIpAddress;
    WCHAR           szIpAddress[128];
    LPWSTR          pAddressEnd;
    WDFMEMORY       wdfOutputMemory = NULL;
    BOOLEAN         bEmpty;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    if (csFlowDeleted == pFlowData->enContextState)
    {
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    ASSERT(pFlowData == pFlowData->pThis);
    bInbound = (BOOLEAN) (FWP_DIRECTION_INBOUND == pFlowData->enPacketDirection);
    if (NULL != NET_BUFFER_LIST_NEXT_NBL(netBufferList))
    {
        FwpsFreeCloneNetBufferList(
            netBufferList,
            0
            );
        //push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    else
    {
        FwpsFreeCloneNetBufferList(
            netBufferList,
            0
            );
    }
    pFlowData->pTcpResponceBufferList = NULL;
    wdfRequestQueue = pFlowData->wdfTcpResponcePermitQueue;
    pFlowData->wdfTcpResponcePermitQueue = NULL;
    if (NULL != wdfRequestQueue)
    {
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(TCP_RESPONCE_APPROVAL)
            );
        WdfObjectDelete(wdfRequestQueue);
    }
    switch (pFlowData->arContextStateStack[i])
    {
    case csTcpPermitResponceDone:
        goto _cont14;
    case csTcpWaitPermitResponce:
    _cont14 :
        pFlowData->enContextState = csTcpPermitResponceDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpWaitResponceInjectDone:
        if (bInbound)
        {
            pFlowData->enContextState = csTcpWaitReadQuery;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        else
        {
            pFlowData->enContextState = csTcpWaitReadResponce;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        break;
    case csTcpQueryMoreData02:
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpClientDisconnect:
    case csTcpServerDisconnect:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_QUEUE,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine"
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI allocatedStreamDnsResponceCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT   wdfFlowFileObject;
    PFLOW_DATA      pFlowData;
    WDFREQUEST      wdfPendedRequest;
    NTSTATUS        status = STATUS_SUCCESS;
    PMDL            _pMdl;
    ULONG_PTR       Information;
    BOOLEAN         bInbound;
    WDFDEVICE       wdfDeviceObject;
    WDFQUEUE        wdfRequestQueue;
    int             i = 0;
    UINT32          ulInboundCount = 0;
    PLIST_ENTRY     pListEntry, pLastLE;
    PFLOW_DATA      pFlowContext = NULL;
    BOOLEAN         bIPv6;
    IN6_ADDR        stRemoteAddress;
    UINT32          ulRemoteAddress = 0, ulRemoteAddressN = 0;
    UINT16          usRemotePort;
    BOOLEAN         bTestIpV4;
    IN_ADDR         stIpAddress;
    WCHAR           szIpAddress[128];
    LPWSTR          pAddressEnd;
    WDFMEMORY       wdfOutputMemory = NULL;
    BOOLEAN         bEmpty;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    ASSERT(pFlowData == pFlowData->pThis);
    if (pFlowData->pTcpResponceInjectBufferList != netBufferList)
    {
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    bInbound = (BOOLEAN) (FWP_DIRECTION_INBOUND == pFlowData->enPacketDirection);
    _pMdl = pFlowData->pTcpResponceMdl;
    ASSERT(NULL != _pMdl);
    IoFreeMdl(_pMdl);
    ExFreePoolWithTag(
        _pMdl->MappedSystemVa,
        POOL_TAG
        );
    FwpsFreeNetBufferList(
        netBufferList
        );
    pFlowData->pTcpResponceMdl = NULL;
    pFlowData->pTcpResponceInjectBufferList = NULL;
    wdfRequestQueue = pFlowData->wdfTcpResponceInjectQueue;
    pFlowData->wdfTcpResponceInjectQueue = NULL;
    if (NULL != wdfRequestQueue)
    {
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        Information = pFlowData->nTcpResponceInjectDataSize;
        pFlowData->nTcpResponceInjectDataSize = 0;
        ASSERT(0 != Information);
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            Information
            );
        WdfObjectDelete(wdfRequestQueue);
    }
    switch (pFlowData->arContextStateStack[i])
    {
    case csTcpWaitReplaceResponceDone:
        pFlowData->enContextState = csTcpReplaceResponceDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpWaitResponceInjectDone:
        if (bInbound)
        {
            pFlowData->enContextState = csTcpWaitReadQuery;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        else
        {
            pFlowData->enContextState = csTcpWaitReadResponce;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        }
        break;
    case csTcpQueryMoreData02:
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        break;
    case csTcpClientDisconnect:
    case csTcpServerDisconnect:
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_QUEUE,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine"
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI clonedDatagramDnsResponceCompletionFn(
    __in     VOID *context,
    __inout  NET_BUFFER_LIST *netBufferList,
    __in     BOOLEAN dispatchLevel
    )
{
    WDFFILEOBJECT       wdfFlowFileObject = NULL;
    WDFQUEUE            wdfFlowQueue;
    int                 nFileIndex, nThreadIndex;
    PFLOW_DATA          pFlowData;
    WDFREQUEST          wdfPendedRequest;
    NTSTATUS            status = STATUS_SUCCESS;
    WSACMSGHDR*         _pControlData = NULL;
    WDFDEVICE           wdfDeviceObject;
    WDFQUEUE            wdfRequestQueue;
    WDFMEMORY           wdfOutputMemory = NULL;
    PLIST_ENTRY         pListEntry, pFirstLE, pLastLE, pPrevLE;
    PFLOW_DATA          pFlowContext = NULL, pFirstFlowContext = NULL;
    UINT32              ulInboundCount = 0;
    BOOLEAN             bEmpty, bIPv6;
    UINT32              ulRemoteAddress = 0, ulRemoteAddressN = 0;
    FWP_BYTE_ARRAY16    stRemoteAddress = { 0 };
    IN_ADDR             stIpAddress;
    IN6_ADDR            stIp6Address;
    WCHAR               szIpAddress[128];
    LPWSTR              pAddressEnd;
    UINT16              usRemotePort;
    BOOLEAN             bTestIpV4;
    UNREFERENCED_PARAMETER(dispatchLevel);
    pFlowData = (PFLOW_DATA) context;
    ASSERT(NULL != pFlowData);
    wdfFlowFileObject = pFlowData->wdfFlowFileObject;
    ASSERT(NULL != wdfFlowFileObject);
    wdfDeviceObject = g_wdfControlDevice;
    WdfObjectAcquireLock(wdfDeviceObject);
    if ((csNotRun == pFlowData->enContextState) || (csFlowDeleted == pFlowData->enContextState))
    {
        WdfObjectReleaseLock(wdfDeviceObject);
        return;
    }
    ASSERT(pFlowData == pFlowData->pThis);
    FwpsFreeCloneNetBufferList(
        netBufferList,
        0
        );
    bIPv6 = pFlowData->bIPv6;
    if (bIPv6)
    {
        IPv6CopyAddress(
            &stRemoteAddress,
            &pFlowData->stRemoteAddressV6
            );
    }
    else
    {
        ulRemoteAddress = pFlowData->nRemoteAddressV4;
        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
    }
    usRemotePort = pFlowData->usRemotePort;
    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
    if (bTestIpV4)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
    }
    switch (pFlowData->enContextState)
    {
    case csUdpWaitResponce1:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host will Elaborated on state \"csUdpWaitResponce1\"."
                );
        }
        ASSERT(pFlowData->pUdpResponceCloneBufferList == netBufferList);
        pFlowData->pUdpResponceCloneBufferList = NULL;
        _pControlData = pFlowData->stUdpResponceSendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponceSendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        pFlowData->bUdpFlow1Done = TRUE;
        if (!IsListEmpty(&g_stUdpInboundList))
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        pFirstFlowContext = pFlowContext;
                        ulInboundCount++;
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        pFirstFlowContext = pFlowContext;
                        ulInboundCount++;
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        pFlowData->enContextState = csUdpFlow1Done;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        if (ulInboundCount > 1)
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bIPv6 = FALSE;
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                        if (bEmpty)
                        {
                            break;
                        }
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        if (NULL != pFlowContext->pUdpQuery2CloneBufferList)
                        {
                            FwpsFreeCloneNetBufferList(
                                pFlowContext->pUdpQuery2CloneBufferList,
                                0
                                );
                            pFlowContext->pUdpQuery2CloneBufferList = NULL;
                        }
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                        if (bEmpty)
                        {
                            break;
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
            if (!IsListEmpty(&g_stUdpAcceptNotifyList))
            {
                pListEntry = g_stUdpAcceptNotifyList.Blink;
                pFirstLE = g_stUdpAcceptNotifyList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
            {
                pListEntry = g_stUdpALEAcceptRecvList.Blink;
                pFirstLE = g_stUdpALEAcceptRecvList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Blink;
                pFirstLE = g_stUdpALEAcceptPendedList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpFlowEstablishPended:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            if (NULL != pFlowContext->pUdpQueryCloneBufferList)
                            {
                                FwpsFreeCloneNetBufferList(
                                    pFlowContext->pUdpQueryCloneBufferList,
                                    0
                                    );
                                pFlowContext->pUdpQueryCloneBufferList = NULL;
                            }
                            if (NULL != pFlowContext->pUdpQueryBufferList)
                            {
                                FwpsDereferenceNetBufferList(
                                    pFlowContext->pUdpQueryBufferList,
                                    FALSE
                                    );
                                pFlowContext->pUdpQueryBufferList = NULL;
                            }
                            if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->bUdpQueryClassifyPended = FALSE;
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpFlowEstablishPended:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            if (NULL != pFlowContext->pUdpQueryBufferList)
                            {
                                FwpsDereferenceNetBufferList(
                                    pFlowContext->pUdpQueryBufferList,
                                    FALSE
                                    );
                                pFlowContext->pUdpQueryBufferList = NULL;
                            }
                            if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->bUdpQueryClassifyPended = FALSE;
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
            {
                pListEntry = g_stUdpALEFlowEstablishList.Blink;
                pFirstLE = g_stUdpALEFlowEstablishList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpAcceptedRecv:
                                break;
                            case csUdpWaitPermitQuery:
                                if (!pFlowContext->bUdpQueryClassifyPended)
                                {
                                    ASSERT(FALSE);
                                }
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->bUdpQueryClassifyPended = FALSE;
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpAcceptedRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->bUdpQueryClassifyPended = FALSE;
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            if (bEmpty)
                            {
                                break;
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                ulInboundCount = 0;
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        IPv6CopyAddress(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            bIPv6 = pFlowData->bIPv6;
            if (bIPv6)
            {
                IPv6CopyAddress(
                    &stRemoteAddress,
                    &pFlowData->stRemoteAddressV6
                    );
            }
            else
            {
                ulRemoteAddress = pFlowData->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
            }
            usRemotePort = pFlowData->usRemotePort;
            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
            if (bTestIpV4)
            {
                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                    szIpAddress,
                    usRemotePort
                    );
            }
            if (bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Posible UDP-Attack to DNS port from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            g_bFiltersChangeInProgress = TRUE;
            wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue;
            ASSERT(NULL != wdfRequestQueue);
            pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowData,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            WdfObjectDelete(wdfRequestQueue);
            WdfObjectReleaseLock(g_wdfControlDevice);
            pFlowData->enContextState = csUdpFlowSetFirewallEvent;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V6,
                    g_nDatagramIdV6
                    );
            }
            else
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V4,
                    g_nDatagramIdV4
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            return;
        }
        if (1 == ulInboundCount)
        {
            pFlowContext = pFirstFlowContext;
            switch (pFlowContext->enContextState)
            {
            case csUdpInboundPended:
                break;
            default:
                ASSERT(FALSE);
            }
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            pFlowData->usRemotePort = pFlowContext->usRemotePort;
            pFlowData->interfaceIndex = pFlowContext->interfaceIndex;
            pFlowData->subInterfaceIndex = pFlowContext->subInterfaceIndex;
            pFlowData->pUdpQuery2BufferList = pFlowContext->pUdpQuery2BufferList;
            pFlowContext->pUdpQuery2BufferList = NULL;
            pFlowData->ulUdpQuery2BufferSize = pFlowContext->ulUdpQuery2BufferSize;
            pFlowContext->ulUdpQuery2BufferSize = 0;
            pFlowData->ulUdpQuery2DataOffset = pFlowContext->ulUdpQuery2DataOffset;
            pFlowContext->ulUdpQuery2DataOffset = 0;
            pFlowData->ulUdpQuery2PacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
            pFlowContext->ulUdpQuery2PacketOffset = 0;
            pFlowData->ulUdpQuery2DataLength = pFlowContext->ulUdpQuery2DataLength;
            pFlowContext->ulUdpQuery2DataLength = 0;
            pFlowData->enUdpQuery2CompartmentID = pFlowContext->enUdpQuery2CompartmentID;
            pFlowData->ulUdpQuery2IpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
            pFlowContext->ulUdpQuery2IpHeaderSize = 0;
            pFlowData->ulUdpQuery2TransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
            pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
            pFlowData->bUdpNotInboundTransport = pFlowContext->bUdpNotInboundTransport;
            pFlowContext->bUdpNotInboundTransport = FALSE;
            pFlowData->bUdpQueryClassifyPended = TRUE;
            pFlowContext->bIPv6 = FALSE;
            pFlowContext->bUdpQueryClassifyPended = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            //ASSERT(FALSE);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            pFlowData->ulUdpQueryCount++;
            if (pFlowData->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Repeated UDP-Query from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            wdfRequestQueue = pFlowData->wdfWaitUdpQuery2Queue;
            ASSERT(NULL != wdfRequestQueue);
            pFlowData->wdfWaitUdpQuery2Queue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowData,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            WdfObjectDelete(wdfRequestQueue);
            pFlowData->enContextState = csUdpWaitReadQuery2;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        bIPv6 = pFlowData->bIPv6;
        if (bIPv6)
        {
            IPv6CopyAddress(
                &stRemoteAddress,
                &pFlowData->stRemoteAddressV6
                );
        }
        else
        {
            ulRemoteAddress = pFlowData->nRemoteAddressV4;
            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
        }
        usRemotePort = pFlowData->usRemotePort;
        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Done."
                );
        }
        pFlowData->enContextState = csUdpFlowDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    case csUdpWaitResponce2:
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host will Elaborated on state \"csUdpWaitResponce2\"."
                );
        }
        ASSERT(pFlowData->pUdpResponce2CloneBufferList == netBufferList);
        pFlowData->pUdpResponce2CloneBufferList = NULL;
        _pControlData = pFlowData->stUdpResponce2SendParams.controlData;
        if (NULL != _pControlData)
        {
            ExFreePoolWithTag(
                _pControlData,
                POOL_TAG
                );
        }
        RtlZeroMemory(
            &pFlowData->stUdpResponce2SendParams,
            sizeof(FWPS_TRANSPORT_SEND_PARAMS)
            );
        if (!IsListEmpty(&g_stUdpInboundList))
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        pFirstFlowContext = pFlowContext;
                        ulInboundCount++;
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        pFirstFlowContext = pFlowContext;
                        ulInboundCount++;
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (ulInboundCount > 0)
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (bIPv6 && pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bIPv6 = FALSE;
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                    }
                }
                else if ((!bIPv6) && (!pFlowContext->bIPv6))
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        if (NULL != pFlowContext->pUdpQuery2CloneBufferList)
                        {
                            FwpsFreeCloneNetBufferList(
                                pFlowContext->pUdpQuery2CloneBufferList,
                                0
                                );
                            pFlowContext->pUdpQuery2CloneBufferList = NULL;
                        }
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
            if (!IsListEmpty(&g_stUdpAcceptNotifyList))
            {
                pListEntry = g_stUdpAcceptNotifyList.Blink;
                pFirstLE = g_stUdpAcceptNotifyList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
            {
                pListEntry = g_stUdpALEAcceptRecvList.Blink;
                pFirstLE = g_stUdpALEAcceptRecvList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                pListEntry = g_stUdpALEAcceptPendedList.Blink;
                pFirstLE = g_stUdpALEAcceptPendedList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (csUdpWaitReadQuery != pFlowContext->enContextState)
                    {
                        if (bIPv6 && pFlowContext->bIPv6)
                        {
                            if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                            {
                                switch (pFlowContext->enContextState)
                                {
                                case csUdpFlowEstablishPended:
                                    break;
                                default:
                                    ASSERT(FALSE);
                                }
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                if (NULL != pFlowContext->pUdpQueryCloneBufferList)
                                {
                                    FwpsFreeCloneNetBufferList(
                                        pFlowContext->pUdpQueryCloneBufferList,
                                        0
                                        );
                                    pFlowContext->pUdpQueryCloneBufferList = NULL;
                                }
                                if (NULL != pFlowContext->pUdpQueryBufferList)
                                {
                                    FwpsDereferenceNetBufferList(
                                        pFlowContext->pUdpQueryBufferList,
                                        FALSE
                                        );
                                    pFlowContext->pUdpQueryBufferList = NULL;
                                }
                                if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                                {
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                    ASSERT(NULL != wdfRequestQueue);
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        status = WdfRequestRetrieveOutputMemory(
                                            wdfPendedRequest,
                                            &wdfOutputMemory
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        status = WdfMemoryCopyFromBuffer(
                                            wdfOutputMemory,
                                            0,
                                            pFlowContext,
                                            sizeof(FLOW_DATA)
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_END_OF_FILE,
                                            sizeof(FLOW_DATA)
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                    ASSERT(NULL != wdfFlowFileObject);
                                    wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                    nFileIndex = pFlowContext->nFileIndex;
                                    nThreadIndex = pFlowContext->nThreadIndex;
                                    RtlZeroMemory(
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    pFlowContext->pThis = pFlowContext;
                                    pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                    pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                    pFlowContext->nFileIndex = nFileIndex;
                                    pFlowContext->nThreadIndex = nThreadIndex;
                                    pFlowContext->enFlowDataOwner = foFreeFileList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stFreeFileList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                else
                                {
                                    pFlowContext->bUdpQueryClassifyPended = FALSE;
                                    pFlowContext->bIPv6 = FALSE;
                                    pFlowContext->enContextState = csWaitQueryStarted;
                                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                    pFlowContext->enFlowDataOwner = foAcceptableList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stAcceptableList,
                                        &pFlowContext->listEntry
                                        );
                                }
                            }
                        }
                        else if ((!bIPv6) && (!pFlowContext->bIPv6))
                        {
                            if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                            {
                                switch (pFlowContext->enContextState)
                                {
                                case csUdpFlowEstablishPended:
                                    break;
                                default:
                                    ASSERT(FALSE);
                                }
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                if (NULL != pFlowContext->pUdpQueryBufferList)
                                {
                                    FwpsDereferenceNetBufferList(
                                        pFlowContext->pUdpQueryBufferList,
                                        FALSE
                                        );
                                    pFlowContext->pUdpQueryBufferList = NULL;
                                }
                                if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                                {
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                    ASSERT(NULL != wdfRequestQueue);
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        status = WdfRequestRetrieveOutputMemory(
                                            wdfPendedRequest,
                                            &wdfOutputMemory
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        status = WdfMemoryCopyFromBuffer(
                                            wdfOutputMemory,
                                            0,
                                            pFlowContext,
                                            sizeof(FLOW_DATA)
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_END_OF_FILE,
                                            sizeof(FLOW_DATA)
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                    ASSERT(NULL != wdfFlowFileObject);
                                    wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                    nFileIndex = pFlowContext->nFileIndex;
                                    nThreadIndex = pFlowContext->nThreadIndex;
                                    RtlZeroMemory(
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    pFlowContext->pThis = pFlowContext;
                                    pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                    pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                    pFlowContext->nFileIndex = nFileIndex;
                                    pFlowContext->nThreadIndex = nThreadIndex;
                                    pFlowContext->enFlowDataOwner = foFreeFileList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stFreeFileList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                else
                                {
                                    pFlowContext->bUdpQueryClassifyPended = FALSE;
                                    pFlowContext->bIPv6 = FALSE;
                                    pFlowContext->enContextState = csWaitQueryStarted;
                                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                    pFlowContext->enFlowDataOwner = foAcceptableList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stAcceptableList,
                                        &pFlowContext->listEntry
                                        );
                                }
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
            {
                pListEntry = g_stUdpALEFlowEstablishList.Blink;
                pFirstLE = g_stUdpALEFlowEstablishList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (bIPv6 && pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(&stRemoteAddress, &pFlowContext->stRemoteAddressV6))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpAcceptedRecv:
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                                {
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                    ASSERT(NULL != wdfRequestQueue);
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        status = WdfRequestRetrieveOutputMemory(
                                            wdfPendedRequest,
                                            &wdfOutputMemory
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        status = WdfMemoryCopyFromBuffer(
                                            wdfOutputMemory,
                                            0,
                                            pFlowContext,
                                            sizeof(FLOW_DATA)
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_END_OF_FILE,
                                            sizeof(FLOW_DATA)
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                    ASSERT(NULL != wdfFlowFileObject);
                                    wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                    nFileIndex = pFlowContext->nFileIndex;
                                    nThreadIndex = pFlowContext->nThreadIndex;
                                    RtlZeroMemory(
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    pFlowContext->pThis = pFlowContext;
                                    pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                    pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                    pFlowContext->nFileIndex = nFileIndex;
                                    pFlowContext->nThreadIndex = nThreadIndex;
                                    pFlowContext->enFlowDataOwner = foFreeFileList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stFreeFileList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                else
                                {
                                    pFlowContext->bUdpQueryClassifyPended = FALSE;
                                    pFlowContext->bIPv6 = FALSE;
                                    pFlowContext->bUdpNotifyQuery = FALSE;
                                    pFlowContext->enContextState = csWaitQueryStarted;
                                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                    pFlowContext->enFlowDataOwner = foAcceptableList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stAcceptableList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                break;
                            case csUdpWaitPermitQuery:
                            case csUdpPermitQueryDone:
                                if (!pFlowContext->bUdpQueryClassifyPended)
                                {
                                    ASSERT(FALSE);
                                }
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                        }
                    }
                    else if ((!bIPv6) && (!pFlowContext->bIPv6))
                    {
                        if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpAcceptedRecv:
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                                {
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                    if (NULL != wdfRequestQueue)
                                    {
                                        pFlowContext->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_DNSFIREWALL,
                                                "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                                status
                                                );
                                        }
                                        WdfObjectDelete(wdfRequestQueue);
                                    }
                                    wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                    ASSERT(NULL != wdfRequestQueue);
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        status = WdfRequestRetrieveOutputMemory(
                                            wdfPendedRequest,
                                            &wdfOutputMemory
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        status = WdfMemoryCopyFromBuffer(
                                            wdfOutputMemory,
                                            0,
                                            pFlowContext,
                                            sizeof(FLOW_DATA)
                                            );
                                        ASSERT(NT_SUCCESS(status));
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_END_OF_FILE,
                                            sizeof(FLOW_DATA)
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                    ASSERT(NULL != wdfFlowFileObject);
                                    wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                    nFileIndex = pFlowContext->nFileIndex;
                                    nThreadIndex = pFlowContext->nThreadIndex;
                                    RtlZeroMemory(
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    pFlowContext->pThis = pFlowContext;
                                    pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                    pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                    pFlowContext->nFileIndex = nFileIndex;
                                    pFlowContext->nThreadIndex = nThreadIndex;
                                    pFlowContext->enFlowDataOwner = foFreeFileList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stFreeFileList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                else
                                {
                                    pFlowContext->bUdpQueryClassifyPended = FALSE;
                                    pFlowContext->bIPv6 = FALSE;
                                    pFlowContext->bUdpNotifyQuery = FALSE;
                                    pFlowContext->enContextState = csWaitQueryStarted;
                                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                    pFlowContext->enFlowDataOwner = foAcceptableList;
                                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                    InsertTailList(
                                        &g_stAcceptableList,
                                        &pFlowContext->listEntry
                                        );
                                }
                                break;
                            case csUdpWaitPermitQuery:
                            case csUdpPermitQueryDone:
                                if (!pFlowContext->bUdpQueryClassifyPended)
                                {
                                    ASSERT(FALSE);
                                }
                                break;
                            default:
                                ASSERT(FALSE);
                            }
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
            }
            if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
            {
                ulInboundCount = 0;
                pListEntry = g_stUdpALEAcceptPendedList.Flink;
                pLastLE = g_stUdpALEAcceptPendedList.Blink;
                for (;;)
                {
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bUdpQueryClassifyPended)
                    {
                        ulInboundCount++;
                        break;
                    }
                    if (pListEntry == pLastLE)
                    {
                        break;
                    }
                    pListEntry = pListEntry->Flink;
                }
                if (ulInboundCount > 0)
                {
                    bIPv6 = pFlowContext->bIPv6;
                    if (bIPv6)
                    {
                        IPv6CopyAddress(
                            &stRemoteAddress,
                            &pFlowContext->stRemoteAddressV6
                            );
                    }
                    else
                    {
                        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                    }
                    usRemotePort = pFlowContext->usRemotePort;
                    bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                    if (bTestIpV4)
                    {
                        stIpAddress.S_un.S_addr = ulRemoteAddressN;
                        pAddressEnd = RtlIpv4AddressToStringW(
                            &stIpAddress,
                            szIpAddress
                            );
                        TraceEvents(
                            TRACE_LEVEL_INFORMATION,
                            TRACE_DNSFIREWALL,
                            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                            szIpAddress,
                            usRemotePort
                            );
                    }
                    pFlowContext->bUdpQueryClassifyPended = TRUE;
                    pFlowContext->ulUdpQueryCount++;
                    pFlowContext->enContextState = csUdpWaitReadQuery;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    //ASSERT(FALSE);
                    wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                    ASSERT(NULL != wdfRequestQueue);
                    pFlowContext->wdfWaitDnsQueryQueue = NULL;
                    status = WdfIoQueueRetrieveNextRequest(
                        wdfRequestQueue,
                        &wdfPendedRequest
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfRequestRetrieveOutputMemory(
                        wdfPendedRequest,
                        &wdfOutputMemory
                        );
                    ASSERT(NT_SUCCESS(status));
                    status = WdfMemoryCopyFromBuffer(
                        wdfOutputMemory,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA)
                        );
                    ASSERT(NT_SUCCESS(status));
                    WdfRequestCompleteWithInformation(
                        wdfPendedRequest,
                        status,
                        sizeof(FLOW_DATA)
                        );
                    WdfObjectDelete(wdfRequestQueue);
                }
            }
            bIPv6 = pFlowData->bIPv6;
            if (bIPv6)
            {
                IPv6CopyAddress(
                    &stRemoteAddress,
                    &pFlowData->stRemoteAddressV6
                    );
            }
            else
            {
                ulRemoteAddress = pFlowData->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
            }
            usRemotePort = pFlowData->usRemotePort;
            bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
            if (bTestIpV4)
            {
                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
                    szIpAddress,
                    usRemotePort
                    );
            }
            if (bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowData->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToStringW(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Posible UDP-Attack to DNS port from host %ws; clent.port = %hu;",
                szIpAddress,
                pFlowData->usRemotePort
                );
            g_bFiltersChangeInProgress = TRUE;
            wdfRequestQueue = pFlowData->wdfWaitUdpSetFirewallFilterQueue;
            ASSERT(NULL != wdfRequestQueue);
            pFlowData->wdfWaitUdpSetFirewallFilterQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowData,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            WdfObjectDelete(wdfRequestQueue);
            pFlowData->enContextState = csUdpFlowSetFirewallEvent;
            push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
            WdfObjectReleaseLock(g_wdfControlDevice);
            if (bIPv6)
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V6,
                    g_nDatagramIdV6
                    );
            }
            else
            {
                status = FwpsFlowRemoveContext(
                    pFlowData->flowHandle,
                    FWPS_LAYER_DATAGRAM_DATA_V4,
                    g_nDatagramIdV4
                    );
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                    status
                    );
            }
            return;
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        bIPv6 = pFlowData->bIPv6;
        if (bIPv6)
        {
            IPv6CopyAddress(
                &stRemoteAddress,
                &pFlowData->stRemoteAddressV6
                );
        }
        else
        {
            ulRemoteAddress = pFlowData->nRemoteAddressV4;
            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
        }
        usRemotePort = pFlowData->usRemotePort;
        bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
        if (bTestIpV4)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Flow Context from Test IpV4 Host %ws will removed; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
        }
        pFlowData->enContextState = csUdpFlowDone;
        push_css(pFlowData->arContextStateStack, pFlowData->enContextState);
        WdfObjectReleaseLock(wdfDeviceObject);
        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
                );
        }
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    default:
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Invalid State Superintendent of State machine = %u",
            pFlowData->enContextState
            );
        break;
    }
    WdfObjectReleaseLock(wdfDeviceObject);
}

void NTAPI onInboundTransportV4Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    static BOOLEAN              bWaitRestartQueueInit = FALSE;
    static WDFQUEUE             wdfWaitRestartQueue = NULL;
    static FLOW_DATA            stFlowDataCopy;
    static WCHAR                szIpAddress[128];
    static BYTE                 baDataArray[512];
    PADDRESSES_DESCRIPTOR       pAddressesDescriptor = NULL;
    UINT32                      ulRemoteAddress, ulI;
    int                         i;
    BOOLEAN                     bLocalNetwork = FALSE;
    PLIST_ENTRY                 pListEntry, pFirstLE, pPrevLE, pLastLE, pNextLE;
    PFLOW_DATA                  pFlowContext = NULL, pInboundContext = NULL;
    UINT32                      ulInboundCount = 0;
    BOOLEAN                     bEmpty;
    FWPS_PACKET_INJECTION_STATE packetState;
    HANDLE                      hInjectionHandle;
    PNET_BUFFER_LIST            pNetBufferList;
    WDFFILEOBJECT               wdfInjectDataObject = NULL;
    WDFQUEUE                    wdfRequestQueue;
    WDFREQUEST                  wdfPendedRequest;
    NTSTATUS                    status = STATUS_SUCCESS;
    WDFMEMORY                   wdfOutputMemory;
    WDFFILEOBJECT               wdfFlowFileObject = NULL;
    WDFQUEUE                    wdfFlowQueue;
    int                         nFileIndex, nThreadIndex;
    IPPROTO                     enIpProto;
    BOOLEAN                     bFlowDataCopy = FALSE;
    PNET_BUFFER                 pNetBuffer;
    UINT32                      nDataSize;
    UINT32                      ulUdpDataOffset;
    UINT32                      ulIpHeaderSize;
    UINT32                      ulTransportHeaderSize;
    COMPARTMENT_ID              enUdpCompartmentID;
    UINT32                      ulUdpDataLength;
    UINT16                      usRemotePort;
    UINT32                      ulRemoteAddressN;
    IN_ADDR                     stIpAddress;
    LPWSTR                      pAddressEnd;
    BOOLEAN                     bTestIpV4;
    PBYTE                       pInboundData;
    PDNS_HEADER                 pDnsHeader;
    BOOLEAN                     bDnsNotify = FALSE;
    BOOLEAN                     bInboundExist = FALSE;
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    if (NULL != g_wdfWaitRestartQueue && !bWaitRestartQueueInit)
    {
        bWaitRestartQueueInit = TRUE;
        wdfWaitRestartQueue = g_wdfWaitRestartQueue;
    }
    else if (NULL == g_wdfWaitRestartQueue && bWaitRestartQueueInit)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! (NULL == g_wdfWaitRestartQueue && bWaitRestartQueueInit);"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    pNetBufferList = (PNET_BUFFER_LIST) layerData;
    ASSERT(pNetBufferList != NULL);
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8;
    ASSERT(IPPROTO_UDP == enIpProto);
    hInjectionHandle = g_hInjectionHandleV4;
    ulRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS].value.uint32;
    enUdpCompartmentID = (COMPARTMENT_ID) inMetaValues->compartmentId;
    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE));
    ulIpHeaderSize = inMetaValues->ipHeaderSize;
    ulTransportHeaderSize = inMetaValues->transportHeaderSize;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_PORT].value.uint16;
    pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
    nDataSize = NET_BUFFER_DATA_LENGTH(pNetBuffer);
    ulUdpDataOffset = NET_BUFFER_DATA_OFFSET(pNetBuffer);
    if (0 == nDataSize)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! (0 == nDataSize)!! Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
    if (bTestIpV4)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
    }
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! pAddressesDescriptor == NULL"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! pAddressesDescriptor->m_pDataArray == NULL"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (c_ulLocalHost == ulRemoteAddress)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPublicIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPrivateIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPublicRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPublicRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)!",
            szIpAddress
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackSubnetListLength; ulI++)
    {
        UINT32  ulAddrPart = (ulRemoteAddress & g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpMask);
        if (ulAddrPart == g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpAddr)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because is in Black List Subnet!",
                szIpAddress
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackListLength; ulI++)
    {
        if (ulRemoteAddress == g_stFirewallConfig.aBlackListArray[ulI])
        {
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Blocked because is in Black List!"
                    );
            }
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    packetState = FwpsQueryPacketInjectionState(
        hInjectionHandle,
        pNetBufferList,
        (HANDLE*) &wdfInjectDataObject
        );
    if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
    {
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Reinjected."
                );
        }
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stUdpAcceptNotifyList))
    {
        pListEntry = g_stUdpAcceptNotifyList.Flink;
        pLastLE = g_stUdpAcceptNotifyList.Blink;
        for (;;)
        {
            pNextLE = pListEntry->Flink;
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    bDnsNotify = TRUE;
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    pFlowContext->bUdpNotifyQuery = FALSE;
                    pFlowContext->enContextState = csWaitQueryStarted;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foAcceptableList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    InsertTailList(
                        &g_stAcceptableList,
                        &pFlowContext->listEntry
                        );
                }
            }
            if (pListEntry == pLastLE)
            {
                break;
            }
            pListEntry = pNextLE;
        }
    }
    pInboundData = (PBYTE) NdisGetDataBuffer(
        pNetBuffer,
        nDataSize,
        baDataArray,
        1,
        0
        );
    ASSERT(NULL != pInboundData);
    pDnsHeader = (PDNS_HEADER) pInboundData;
    if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
    {
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! NOTIFY Query from Tested IpV4 Host was Received."
                );
        }
        if (IsListEmpty(&g_stAcceptableList))
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->nRemoteAddressV4 = ulRemoteAddress;
        pFlowContext->nRemoteAddressV4N = ulRemoteAddressN;
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = FALSE;
        pFlowContext->bUdpNotifyQuery = TRUE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpAcceptNotifyList\"."
                );
        }
        pFlowContext->enFlowDataOwner = foUdpAcceptNotifyList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpAcceptNotifyList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)
        )
    {
        if (IsListEmpty(&g_stAcceptableList))
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->nRemoteAddressV4 = ulRemoteAddress;
        pFlowContext->nRemoteAddressV4N = ulRemoteAddressN;
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEAcceptRecvList\"."
                );
        }
        pFlowContext->enFlowDataOwner = foUdpALEAcceptRecvList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEAcceptRecvList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    ulInboundCount = 0;
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (IPPROTO_UDP == pFlowContext->enIpProto))
                {
                    ulInboundCount += pFlowContext->ulUdpQueryCount;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (ulInboundCount > 2)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because exist greater then two UDP-flow for this host; client.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
    {
        pListEntry = g_stUdpALEAcceptRecvList.Blink;
        pFirstLE = g_stUdpALEAcceptRecvList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
    {
        pListEntry = g_stUdpALEAcceptPendedList.Blink;
        pFirstLE = g_stUdpALEAcceptPendedList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
    {
        pListEntry = g_stUdpALEFlowEstablishList.Blink;
        pFirstLE = g_stUdpALEFlowEstablishList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpInboundList))
    {
        pListEntry = g_stUdpInboundList.Blink;
        pFirstLE = g_stUdpInboundList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    bInboundExist = TRUE;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (ulInboundCount > 4)
    {
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (IPPROTO_UDP == pFlowContext->enIpProto))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitApprovalQuery:
                        case csUdpWaitReplaceQuery:
                        case csUdpWaitApprovalQuery2:
                        case csUdpWaitReplaceQuery2:
                            break;
                        default:
                            stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                            pAddressEnd = RtlIpv4AddressToStringW(
                                &stIpAddress,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Host %ws client.port = %hu on state = %u exist in \"g_stFlowedFileList\".",
                                szIpAddress,
                                pFlowContext->usRemotePort,
                                (UINT32) pFlowContext->enContextState
                                );
                            pFlowContext->enContextState = csUdpFlowBreak;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            status = FwpsFlowRemoveContext(
                                pFlowContext->flowHandle,
                                FWPS_LAYER_DATAGRAM_DATA_V4,
                                g_nDatagramIdV4
                                );
                            if (!NT_SUCCESS(status))
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                                    status
                                    );
                            }
                            WdfObjectAcquireLock(g_wdfControlDevice);
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpInboundList))
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
        {
            pListEntry = g_stUdpALEAcceptRecvList.Blink;
            pFirstLE = g_stUdpALEAcceptRecvList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitAcceptRecv:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Blink;
            pFirstLE = g_stUdpALEAcceptPendedList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpFlowEstablishPended:
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            if (NULL != pFlowContext->pUdpQueryCloneBufferList)
                            {
                                FwpsFreeCloneNetBufferList(
                                    pFlowContext->pUdpQueryCloneBufferList,
                                    0
                                    );
                                pFlowContext->pUdpQueryCloneBufferList = NULL;
                            }
                            if (NULL != pFlowContext->pUdpQueryBufferList)
                            {
                                FwpsDereferenceNetBufferList(
                                    pFlowContext->pUdpQueryBufferList,
                                    FALSE
                                    );
                                pFlowContext->pUdpQueryBufferList = NULL;
                            }
                            pFlowContext->bUdpQueryClassifyPended = FALSE;
                            pFlowContext->bUdpNotInboundTransport = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            if (!bFlowDataCopy)
                            {
                                bFlowDataCopy = TRUE;
                                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_NO_MORE_ENTRIES,
                                            0
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                pFlowContext->enContextState = csUdpSetFilterEvent;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                RtlCopyMemory(
                                    &stFlowDataCopy,
                                    pFlowContext,
                                    sizeof(stFlowDataCopy)
                                    );
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            break;
                        case csUdpWaitReadQuery:
                            break;
                        case csUdpWaitApprovalQuery:
                            break;
                        case csUdpPermitQueryPended:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
        {
            pListEntry = g_stUdpALEFlowEstablishList.Blink;
            pFirstLE = g_stUdpALEFlowEstablishList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpAcceptedRecv:
                            break;
                        case csUdpWaitPermitQuery:
                        case csUdpPermitQueryDone:
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ASSERT(FALSE);
                                classifyOut->actionType = FWP_ACTION_BLOCK;
                                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                WdfObjectReleaseLock(g_wdfControlDevice);
                                return;
                            }
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotInboundTransport = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                        {
                            wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitFlowDoneQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            if (NT_SUCCESS(status))
                            {
                                status = WdfRequestRetrieveOutputMemory(
                                    wdfPendedRequest,
                                    &wdfOutputMemory
                                    );
                                ASSERT(NT_SUCCESS(status));
                                status = WdfMemoryCopyFromBuffer(
                                    wdfOutputMemory,
                                    0,
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                ASSERT(NT_SUCCESS(status));
                                WdfRequestCompleteWithInformation(
                                    wdfPendedRequest,
                                    STATUS_END_OF_FILE,
                                    sizeof(FLOW_DATA)
                                    );
                            }
                            else if (STATUS_NO_MORE_ENTRIES != status)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                    status
                                    );
                            }
                            WdfObjectDelete(wdfRequestQueue);
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        ASSERT(bFlowDataCopy);
        pFlowContext = &stFlowDataCopy;
        stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Posible UDP-Attack to DNS port from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowContext->usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        pFlowContext->bFilterGhangePended = TRUE;
        g_bFiltersChangeInProgress = TRUE;
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowContext->wdfWaitUdpSetFirewallFilterQueue = NULL;
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfRequestRetrieveOutputMemory(
            wdfPendedRequest,
            &wdfOutputMemory
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfMemoryCopyFromBuffer(
            wdfOutputMemory,
            0,
            pFlowContext,
            sizeof(FLOW_DATA)
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(FLOW_DATA)
            );
        WdfObjectDelete(wdfRequestQueue);
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (0 == ulInboundCount)
    {
        // Àâòîðèçîâàííûé ïîòîê çàêîí÷èëñÿ, è ïîòîìó òðåáóåòñÿ ïîâòîðíàÿ Àâòîðèçàöèÿ
        if (IsListEmpty(&g_stAcceptableList))
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->nRemoteAddressV4 = ulRemoteAddress;
        pFlowContext->nRemoteAddressV4N = ulRemoteAddressN;
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = TRUE;
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEAcceptRecvList\"."
                );
        }
        pFlowContext->enFlowDataOwner = foUdpALEAcceptRecvList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEAcceptRecvList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IsListEmpty(&g_stAcceptableList))
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        if (NULL != g_wdfWaitRestartQueue)
        {
            status = WdfIoQueueRetrieveNextRequest(
                g_wdfWaitRestartQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                &g_uiRestartStatus,
                sizeof(g_uiRestartStatus)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(g_uiRestartStatus)
                );
            WdfObjectDelete(g_wdfWaitRestartQueue);
            g_wdfWaitRestartQueue = NULL;
        }
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pListEntry = RemoveHeadList(&g_stAcceptableList);
    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
    ASSERT(pFlowContext == pFlowContext->pThis);
    pInboundContext = pFlowContext;
    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
    pFlowContext->enIpProto = IPPROTO_UDP;
    pFlowContext->nRemoteAddressV4 = ulRemoteAddress;
    pFlowContext->nRemoteAddressV4N = ulRemoteAddressN;
    pFlowContext->usRemotePort = usRemotePort;
    pFlowContext->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_INTERFACE_INDEX].value.uint32;
    pFlowContext->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX].value.uint32;
    pFlowContext->pUdpQuery2BufferList = pNetBufferList;
    pFlowContext->ulUdpQuery2BufferSize = nDataSize + ulIpHeaderSize + ulTransportHeaderSize;
    pFlowContext->ulUdpQuery2DataOffset = ulUdpDataOffset;
    pFlowContext->ulUdpQuery2PacketOffset = ulUdpDataOffset - ulIpHeaderSize - ulTransportHeaderSize;
    ulUdpDataLength = nDataSize;
    pFlowContext->ulUdpQuery2DataLength = ulUdpDataLength;
    ASSERT(pFlowContext->ulUdpQuery2DataLength > 0);
    pFlowContext->enUdpQuery2CompartmentID = enUdpCompartmentID;
    pFlowContext->ulUdpQuery2IpHeaderSize = ulIpHeaderSize;
    pFlowContext->ulUdpQuery2TransportHeaderSize = ulTransportHeaderSize;
    FwpsReferenceNetBufferList(
        pNetBufferList,
        TRUE
        );
    pFlowContext->bUdpNotInboundTransport = FALSE;
    pFlowContext->enContextState = csUdpInboundPended;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    if (bTestIpV4)
    {
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpInboundList\"."
            );
    }
    pFlowContext->enFlowDataOwner = foUdpInboundList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stUdpInboundList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    if (bInboundExist) // && bDnsNotify
    {
        ulInboundCount = 0;
        pListEntry = g_stUdpInboundList.Flink;
        pLastLE = g_stUdpInboundList.Blink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (pInboundContext != pFlowContext)
                    )
                {
                    ulInboundCount++;
                    break;
                }
            }
            if (pListEntry == pLastLE)
            {
                break;
            }
            pListEntry = pListEntry->Flink;
        }
        if (1 == ulInboundCount)
        {
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            ulRemoteAddress = pFlowContext->nRemoteAddressV4;
            ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
            usRemotePort = pFlowContext->usRemotePort;
            bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
            pFlowContext->bUdpQueryClassifyPended = TRUE;
            pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
            pFlowContext->ulUdpQueryCount++;
            pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
            pFlowContext->pUdpQuery2BufferList = NULL;
            pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
            pFlowContext->ulUdpQuery2BufferSize = 0;
            pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
            pFlowContext->ulUdpQuery2DataOffset = 0;
            pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
            pFlowContext->ulUdpQuery2PacketOffset = 0;
            pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
            pFlowContext->ulUdpQuery2DataLength = 0;
            pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
            pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
            pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
            pFlowContext->ulUdpQuery2IpHeaderSize = 0;
            pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
            pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
            pFlowContext->enContextState = csUdpWaitReadQuery;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEAcceptPendedList\"."
                    );
            }
            pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            //ASSERT(FALSE);
            InsertTailList(
                &g_stUdpALEAcceptPendedList,
                &pFlowContext->listEntry
                );
            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
            ASSERT(NULL != wdfRequestQueue);
            pFlowContext->wdfWaitDnsQueryQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowContext,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            WdfObjectDelete(wdfRequestQueue);
        }
    }
    WdfObjectReleaseLock(g_wdfControlDevice);
}

void NTAPI onInboundTransportV6Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    static BOOLEAN              bWaitRestartQueueInit = FALSE;
    static WDFQUEUE             wdfWaitRestartQueue = NULL;
    static FLOW_DATA            stFlowDataCopy;
    static WCHAR                szIpAddress[128];
    static BYTE                 baDataArray[512];
    PADDRESSES_DESCRIPTOR       pAddressesDescriptor = NULL;
    FWP_BYTE_ARRAY16            *pRemoteAddress;
    BOOLEAN                     bLocalNetwork = FALSE;
    PLIST_ENTRY                 pListEntry, pFirstLE, pPrevLE, pLastLE, pNextLE;
    PFLOW_DATA                  pFlowContext = NULL, pInboundContext = NULL;
    UINT32                      ulI;
    BOOLEAN                     bEmpty;
    FWPS_PACKET_INJECTION_STATE packetState;
    HANDLE                      hInjectionHandle;
    PNET_BUFFER_LIST            pNetBufferList;
    WDFFILEOBJECT               wdfInjectDataObject = NULL;
    IN6_ADDR                    stIp6Address;
    LPWSTR                      pAddressEnd;
    WDFQUEUE                    wdfRequestQueue;
    WDFREQUEST                  wdfPendedRequest;
    NTSTATUS                    status = STATUS_SUCCESS;
    WDFMEMORY                   wdfOutputMemory;
    WDFFILEOBJECT               wdfFlowFileObject = NULL;
    WDFQUEUE                    wdfFlowQueue;
    int                         nFileIndex, nThreadIndex;
    IPPROTO                     enIpProto;
    BOOLEAN                     bFlowDataCopy = FALSE;
    PNET_BUFFER                 pNetBuffer;
    UINT32                      nDataSize;
    UINT32                      ulUdpDataOffset;
    UINT32                      ulIpHeaderSize;
    UINT32                      ulTransportHeaderSize;
    COMPARTMENT_ID              enUdpCompartmentID;
    UINT32                      ulUdpDataLength = 0;
    UINT32                      ulInboundCount = 0;
    int                         i;
    UINT16                      usRemotePort;
    PBYTE                       pInboundData;
    PDNS_HEADER                 pDnsHeader;
    BOOLEAN                     bDnsNotify = FALSE;
    BOOLEAN                     bInboundExist = FALSE;
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    if (NULL != g_wdfWaitRestartQueue && !bWaitRestartQueueInit)
    {
        bWaitRestartQueueInit = TRUE;
        wdfWaitRestartQueue = g_wdfWaitRestartQueue;
    }
    else if (NULL == g_wdfWaitRestartQueue && bWaitRestartQueueInit)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! (NULL == g_wdfWaitRestartQueue && bWaitRestartQueueInit);"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    pNetBufferList = (PNET_BUFFER_LIST) layerData;
    ASSERT(pNetBufferList != NULL);
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_PROTOCOL].value.uint8;
    ASSERT(IPPROTO_UDP == enIpProto);
    hInjectionHandle = g_hInjectionHandleV6;
    pRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS].value.byteArray16;
    enUdpCompartmentID = (COMPARTMENT_ID) inMetaValues->compartmentId;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE));
    ulIpHeaderSize = inMetaValues->ipHeaderSize;
    ulTransportHeaderSize = inMetaValues->transportHeaderSize;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_PORT].value.uint16;
    pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
    nDataSize = NET_BUFFER_DATA_LENGTH(pNetBuffer);
    ulUdpDataOffset = NET_BUFFER_DATA_OFFSET(pNetBuffer);
    if (0 == nDataSize)
    {
        RtlCopyMemory(
            &stIp6Address,
            pRemoteAddress,
            sizeof(stIp6Address)
            );
        pAddressEnd = RtlIpv6AddressToStringW(
            &stIp6Address,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! (0 == nDataSize)!! Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor->m_pDataArray)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!bfIPv6AddressInIPv6Subnet(pRemoteAddress, c_pGlobalIPv6Subnet))
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPublicIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPrivateIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
    {
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackListV6Length; ulI++)
    {
        if (bfIsIPv6AddressesEqual(pRemoteAddress, &g_stFirewallConfig.aBlackListV6Array[ulI]))
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    packetState = FwpsQueryPacketInjectionState(
        hInjectionHandle,
        pNetBufferList,
        (HANDLE*) &wdfInjectDataObject
        );
    if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stUdpAcceptNotifyList))
    {
        pListEntry = g_stUdpAcceptNotifyList.Flink;
        pLastLE = g_stUdpAcceptNotifyList.Blink;
        for (;;)
        {
            pNextLE = pListEntry->Flink;
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    bDnsNotify = TRUE;
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    pFlowContext->bUdpNotifyQuery = FALSE;
                    pFlowContext->enContextState = csWaitQueryStarted;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foAcceptableList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    InsertTailList(
                        &g_stAcceptableList,
                        &pFlowContext->listEntry
                        );
                }
            }
            if (pListEntry == pLastLE)
            {
                break;
            }
            pListEntry = pNextLE;
        }
    }
    pInboundData = (PBYTE) NdisGetDataBuffer(
        pNetBuffer,
        nDataSize,
        baDataArray,
        1,
        0
        );
    ASSERT(NULL != pInboundData);
    pDnsHeader = (PDNS_HEADER) pInboundData;
    if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
    {
        if (IsListEmpty(&g_stAcceptableList))
        {
            RtlCopyMemory(
                &stIp6Address,
                pRemoteAddress,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->bIPv6 = TRUE;
        IPv6CopyAddress(&pFlowContext->stRemoteAddressV6, pRemoteAddress);
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = FALSE;
        pFlowContext->bUdpNotifyQuery = TRUE;
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        pFlowContext->enFlowDataOwner = foUdpAcceptNotifyList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpAcceptNotifyList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)
        )
    {
        if (IsListEmpty(&g_stAcceptableList))
        {
            RtlCopyMemory(
                &stIp6Address,
                pRemoteAddress,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->bIPv6 = TRUE;
        IPv6CopyAddress(&pFlowContext->stRemoteAddressV6, pRemoteAddress);
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = FALSE;
        pFlowContext->bUdpNotifyQuery = FALSE;
        pFlowContext->bUdpQueryClassifyPended = FALSE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        pFlowContext->enFlowDataOwner = foUdpALEAcceptRecvList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEAcceptRecvList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    ulInboundCount = 0;
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if ((bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    && (IPPROTO_UDP == pFlowContext->enIpProto))
                {
                    ulInboundCount += pFlowContext->ulUdpQueryCount;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (ulInboundCount > 2)
    {
        RtlCopyMemory(
            &stIp6Address,
            pRemoteAddress,
            sizeof(stIp6Address)
            );
        pAddressEnd = RtlIpv6AddressToStringW(
            &stIp6Address,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because exist greater then two UDP-flow for this host; client.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
    {
        pListEntry = g_stUdpALEAcceptRecvList.Blink;
        pFirstLE = g_stUdpALEAcceptRecvList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
    {
        pListEntry = g_stUdpALEAcceptPendedList.Blink;
        pFirstLE = g_stUdpALEAcceptPendedList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
    {
        pListEntry = g_stUdpALEFlowEstablishList.Blink;
        pFirstLE = g_stUdpALEFlowEstablishList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (!IsListEmpty(&g_stUdpInboundList))
    {
        pListEntry = g_stUdpInboundList.Blink;
        pFirstLE = g_stUdpInboundList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    bInboundExist = TRUE;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    if (ulInboundCount > 4)
    {
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                        && (IPPROTO_UDP == pFlowContext->enIpProto))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitApprovalQuery:
                        case csUdpWaitReplaceQuery:
                        case csUdpWaitApprovalQuery2:
                        case csUdpWaitReplaceQuery2:
                            break;
                        default:
                            RtlCopyMemory(
                                &stIp6Address,
                                &pFlowContext->stRemoteAddressV6,
                                sizeof(stIp6Address)
                                );
                            pAddressEnd = RtlIpv6AddressToStringW(
                                &stIp6Address,
                                szIpAddress
                                );
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNSFIREWALL,
                                "%!FUNC! line:%!LINE! %!LEVEL! Host %ws client.port = %hu on state = %u exist in \"g_stFlowedFileList\".",
                                szIpAddress,
                                pFlowContext->usRemotePort,
                                (UINT32) pFlowContext->enContextState
                                );
                            pFlowContext->enContextState = csUdpFlowBreak;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            status = FwpsFlowRemoveContext(
                                pFlowContext->flowHandle,
                                FWPS_LAYER_DATAGRAM_DATA_V6,
                                g_nDatagramIdV6
                                );
                            if (!NT_SUCCESS(status))
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                                    status
                                    );
                            }
                            WdfObjectAcquireLock(g_wdfControlDevice);
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpInboundList))
        {
            pListEntry = g_stUdpInboundList.Blink;
            pFirstLE = g_stUdpInboundList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpInboundPended:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotInboundTransport = FALSE;
                        if (NULL != pFlowContext->pUdpQuery2BufferList)
                        {
                            FwpsDereferenceNetBufferList(
                                pFlowContext->pUdpQuery2BufferList,
                                FALSE
                                );
                            pFlowContext->pUdpQuery2BufferList = NULL;
                        }
                        pFlowContext->bUdpQueryClassifyPended = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEAcceptRecvList))
        {
            pListEntry = g_stUdpALEAcceptRecvList.Blink;
            pFirstLE = g_stUdpALEAcceptRecvList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitAcceptRecv:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotInboundTransport = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Blink;
            pFirstLE = g_stUdpALEAcceptPendedList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpFlowEstablishPended:
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotInboundTransport = FALSE;
                            if (NULL != pFlowContext->pUdpQueryCloneBufferList)
                            {
                                FwpsFreeCloneNetBufferList(
                                    pFlowContext->pUdpQueryCloneBufferList,
                                    0
                                    );
                                pFlowContext->pUdpQueryCloneBufferList = NULL;
                            }
                            if (NULL != pFlowContext->pUdpQueryBufferList)
                            {
                                FwpsDereferenceNetBufferList(
                                    pFlowContext->pUdpQueryBufferList,
                                    FALSE
                                    );
                                pFlowContext->pUdpQueryBufferList = NULL;
                            }
                            pFlowContext->bUdpQueryClassifyPended = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            if (!bFlowDataCopy)
                            {
                                bFlowDataCopy = TRUE;
                                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                    status = WdfIoQueueRetrieveNextRequest(
                                        wdfRequestQueue,
                                        &wdfPendedRequest
                                        );
                                    if (NT_SUCCESS(status))
                                    {
                                        WdfRequestCompleteWithInformation(
                                            wdfPendedRequest,
                                            STATUS_NO_MORE_ENTRIES,
                                            0
                                            );
                                    }
                                    else if (STATUS_NO_MORE_ENTRIES != status)
                                    {
                                        TraceEvents(
                                            TRACE_LEVEL_ERROR,
                                            TRACE_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                pFlowContext->enContextState = csUdpSetFilterEvent;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                RtlCopyMemory(
                                    &stFlowDataCopy,
                                    pFlowContext,
                                    sizeof(stFlowDataCopy)
                                    );
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                            {
                                wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                                if (NULL != wdfRequestQueue)
                                {
                                    pFlowContext->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_DNSFIREWALL,
                                            "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                            status
                                            );
                                    }
                                    WdfObjectDelete(wdfRequestQueue);
                                }
                                wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                                ASSERT(NULL != wdfRequestQueue);
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    status = WdfRequestRetrieveOutputMemory(
                                        wdfPendedRequest,
                                        &wdfOutputMemory
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    status = WdfMemoryCopyFromBuffer(
                                        wdfOutputMemory,
                                        0,
                                        pFlowContext,
                                        sizeof(FLOW_DATA)
                                        );
                                    ASSERT(NT_SUCCESS(status));
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_END_OF_FILE,
                                        sizeof(FLOW_DATA)
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                                wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                                ASSERT(NULL != wdfFlowFileObject);
                                wdfFlowQueue = pFlowContext->wdfFlowQueue;
                                nFileIndex = pFlowContext->nFileIndex;
                                nThreadIndex = pFlowContext->nThreadIndex;
                                RtlZeroMemory(
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                pFlowContext->pThis = pFlowContext;
                                pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                                pFlowContext->wdfFlowQueue = wdfFlowQueue;
                                pFlowContext->nFileIndex = nFileIndex;
                                pFlowContext->nThreadIndex = nThreadIndex;
                                pFlowContext->enFlowDataOwner = foFreeFileList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stFreeFileList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            else
                            {
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                            break;
                        case csUdpWaitReadQuery:
                            break;
                        case csUdpWaitApprovalQuery:
                            break;
                        case csUdpPermitQueryPended:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        if (!IsListEmpty(&g_stUdpALEFlowEstablishList))
        {
            pListEntry = g_stUdpALEFlowEstablishList.Blink;
            pFirstLE = g_stUdpALEFlowEstablishList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (pFlowContext->bIPv6)
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpAcceptedRecv:
                            break;
                        case csUdpWaitPermitQuery:
                        case csUdpPermitQueryDone:
                            if (!pFlowContext->bUdpQueryClassifyPended)
                            {
                                ASSERT(FALSE);
                                classifyOut->actionType = FWP_ACTION_BLOCK;
                                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                WdfObjectReleaseLock(g_wdfControlDevice);
                                return;
                            }
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotInboundTransport = FALSE;
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        if (!bFlowDataCopy)
                        {
                            bFlowDataCopy = TRUE;
                            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->wdfWaitFlowDoneQueue = NULL;
                                status = WdfIoQueueRetrieveNextRequest(
                                    wdfRequestQueue,
                                    &wdfPendedRequest
                                    );
                                if (NT_SUCCESS(status))
                                {
                                    WdfRequestCompleteWithInformation(
                                        wdfPendedRequest,
                                        STATUS_NO_MORE_ENTRIES,
                                        0
                                        );
                                }
                                else if (STATUS_NO_MORE_ENTRIES != status)
                                {
                                    TraceEvents(
                                        TRACE_LEVEL_ERROR,
                                        TRACE_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            pFlowContext->enContextState = csUdpSetFilterEvent;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            RtlCopyMemory(
                                &stFlowDataCopy,
                                pFlowContext,
                                sizeof(stFlowDataCopy)
                                );
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else if (NULL == pFlowContext->wdfWaitDnsQueryQueue)
                        {
                            wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitUdpQuery2Queue;
                            if (NULL != wdfRequestQueue)
                            {
                                pFlowContext->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_DNSFIREWALL,
                                        "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                        status
                                        );
                                }
                                WdfObjectDelete(wdfRequestQueue);
                            }
                            wdfRequestQueue = pFlowContext->wdfWaitFlowDoneQueue;
                            ASSERT(NULL != wdfRequestQueue);
                            pFlowContext->wdfWaitFlowDoneQueue = NULL;
                            status = WdfIoQueueRetrieveNextRequest(
                                wdfRequestQueue,
                                &wdfPendedRequest
                                );
                            if (NT_SUCCESS(status))
                            {
                                status = WdfRequestRetrieveOutputMemory(
                                    wdfPendedRequest,
                                    &wdfOutputMemory
                                    );
                                ASSERT(NT_SUCCESS(status));
                                status = WdfMemoryCopyFromBuffer(
                                    wdfOutputMemory,
                                    0,
                                    pFlowContext,
                                    sizeof(FLOW_DATA)
                                    );
                                ASSERT(NT_SUCCESS(status));
                                WdfRequestCompleteWithInformation(
                                    wdfPendedRequest,
                                    STATUS_END_OF_FILE,
                                    sizeof(FLOW_DATA)
                                    );
                            }
                            else if (STATUS_NO_MORE_ENTRIES != status)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNSFIREWALL,
                                    "%!FUNC! line:%!LINE! %!LEVEL! \"WdfIoQueueRetrieveNextRequest\" return %!STATUS!",
                                    status
                                    );
                            }
                            WdfObjectDelete(wdfRequestQueue);
                            wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
                            ASSERT(NULL != wdfFlowFileObject);
                            wdfFlowQueue = pFlowContext->wdfFlowQueue;
                            nFileIndex = pFlowContext->nFileIndex;
                            nThreadIndex = pFlowContext->nThreadIndex;
                            RtlZeroMemory(
                                pFlowContext,
                                sizeof(FLOW_DATA)
                                );
                            pFlowContext->pThis = pFlowContext;
                            pFlowContext->wdfFlowFileObject = wdfFlowFileObject;
                            pFlowContext->wdfFlowQueue = wdfFlowQueue;
                            pFlowContext->nFileIndex = nFileIndex;
                            pFlowContext->nThreadIndex = nThreadIndex;
                            pFlowContext->enFlowDataOwner = foFreeFileList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stFreeFileList,
                                &pFlowContext->listEntry
                                );
                        }
                        else
                        {
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
        }
        ASSERT(bFlowDataCopy);
        pFlowContext = &stFlowDataCopy;
        RtlCopyMemory(
            &stIp6Address,
            pRemoteAddress,
            sizeof(stIp6Address)
            );
        pAddressEnd = RtlIpv6AddressToStringW(
            &stIp6Address,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Posible UDP-Attack to DNS port from host %ws; clent.port = %hu;",
            szIpAddress,
            pFlowContext->usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        g_bFiltersChangeInProgress = TRUE;
        wdfRequestQueue = pFlowContext->wdfWaitUdpSetFirewallFilterQueue;
        ASSERT(NULL != wdfRequestQueue);
        pFlowContext->wdfWaitUdpSetFirewallFilterQueue = NULL;
        status = WdfIoQueueRetrieveNextRequest(
            wdfRequestQueue,
            &wdfPendedRequest
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfRequestRetrieveOutputMemory(
            wdfPendedRequest,
            &wdfOutputMemory
            );
        ASSERT(NT_SUCCESS(status));
        status = WdfMemoryCopyFromBuffer(
            wdfOutputMemory,
            0,
            pFlowContext,
            sizeof(FLOW_DATA)
            );
        ASSERT(NT_SUCCESS(status));
        WdfRequestCompleteWithInformation(
            wdfPendedRequest,
            status,
            sizeof(FLOW_DATA)
            );
        WdfObjectDelete(wdfRequestQueue);
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (0 == ulInboundCount)
    {
        // Àâòîðèçîâàííûé ïîòîê çàêîí÷èëñÿ, è ïîòîìó òðåáóåòñÿ ïîâòîðíàÿ Àâòîðèçàöèÿ
        if (IsListEmpty(&g_stAcceptableList))
        {
            RtlCopyMemory(
                &stIp6Address,
                pRemoteAddress,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            if (NULL != g_wdfWaitRestartQueue)
            {
                status = WdfIoQueueRetrieveNextRequest(
                    g_wdfWaitRestartQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    &g_uiRestartStatus,
                    sizeof(g_uiRestartStatus)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(g_uiRestartStatus)
                    );
                WdfObjectDelete(g_wdfWaitRestartQueue);
                g_wdfWaitRestartQueue = NULL;
            }
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        pListEntry = RemoveHeadList(&g_stAcceptableList);
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
        pFlowContext->enIpProto = IPPROTO_UDP;
        pFlowContext->bIPv6 = TRUE;
        IPv6CopyAddress(&pFlowContext->stRemoteAddressV6, pRemoteAddress);
        pFlowContext->usRemotePort = usRemotePort;
        pFlowContext->bUdpNotInboundTransport = TRUE;
        pFlowContext->enContextState = csUdpWaitAcceptRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        pFlowContext->enFlowDataOwner = foUdpALEAcceptRecvList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEAcceptRecvList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (IsListEmpty(&g_stAcceptableList))
    {
        RtlCopyMemory(
            &stIp6Address,
            pRemoteAddress,
            sizeof(stIp6Address)
            );
        pAddressEnd = RtlIpv6AddressToStringW(
            &stIp6Address,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stAcceptableList\" is Empty!! Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        if (NULL != g_wdfWaitRestartQueue)
        {
            status = WdfIoQueueRetrieveNextRequest(
                g_wdfWaitRestartQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                &g_uiRestartStatus,
                sizeof(g_uiRestartStatus)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(g_uiRestartStatus)
                );
            WdfObjectDelete(g_wdfWaitRestartQueue);
            g_wdfWaitRestartQueue = NULL;
        }
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pListEntry = RemoveHeadList(&g_stAcceptableList);
    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
    ASSERT(pFlowContext == pFlowContext->pThis);
    pInboundContext = pFlowContext;
    wdfFlowFileObject = pFlowContext->wdfFlowFileObject;
    pFlowContext->enIpProto = IPPROTO_UDP;
    pFlowContext->bIPv6 = TRUE;
    IPv6CopyAddress(&pFlowContext->stRemoteAddressV6, pRemoteAddress);
    pFlowContext->usRemotePort = usRemotePort;
    pFlowContext->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_INTERFACE_INDEX].value.uint32;
    pFlowContext->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_SUB_INTERFACE_INDEX].value.uint32;
    pFlowContext->pUdpQuery2BufferList = pNetBufferList;
    pFlowContext->ulUdpQuery2BufferSize = nDataSize + ulIpHeaderSize + ulTransportHeaderSize;
    pFlowContext->ulUdpQuery2DataOffset = ulUdpDataOffset;
    pFlowContext->ulUdpQuery2PacketOffset = ulUdpDataOffset - ulIpHeaderSize - ulTransportHeaderSize;
    ulUdpDataLength = nDataSize;
    pFlowContext->ulUdpQuery2DataLength = ulUdpDataLength;
    ASSERT(pFlowContext->ulUdpQuery2DataLength > 0);
    pFlowContext->enUdpQuery2CompartmentID = enUdpCompartmentID;
    pFlowContext->ulUdpQuery2IpHeaderSize = ulIpHeaderSize;
    pFlowContext->ulUdpQuery2TransportHeaderSize = ulTransportHeaderSize;
    FwpsReferenceNetBufferList(
        pNetBufferList,
        TRUE
        );
    pFlowContext->bUdpNotInboundTransport = FALSE;
    pFlowContext->enContextState = csUdpInboundPended;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    pFlowContext->enFlowDataOwner = foUdpInboundList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stUdpInboundList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    if (bInboundExist) // && bDnsNotify
    {
        ulInboundCount = 0;
        pListEntry = g_stUdpInboundList.Flink;
        pLastLE = g_stUdpInboundList.Blink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                    && (pInboundContext != pFlowContext)
                    )
                {
                    ulInboundCount++;
                    break;
                }
            }
            if (pListEntry == pLastLE)
            {
                break;
            }
            pListEntry = pListEntry->Flink;
        }
        if (1 == ulInboundCount)
        {
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            usRemotePort = pFlowContext->usRemotePort;
            pFlowContext->bUdpQueryClassifyPended = TRUE;
            pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
            pFlowContext->ulUdpQueryCount++;
            pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
            pFlowContext->pUdpQuery2BufferList = NULL;
            pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
            pFlowContext->ulUdpQuery2BufferSize = 0;
            pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
            pFlowContext->ulUdpQuery2DataOffset = 0;
            pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
            pFlowContext->ulUdpQuery2PacketOffset = 0;
            pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
            pFlowContext->ulUdpQuery2DataLength = 0;
            pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
            pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
            pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
            pFlowContext->ulUdpQuery2IpHeaderSize = 0;
            pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
            pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
            pFlowContext->enContextState = csUdpWaitReadQuery;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            //ASSERT(FALSE);
            InsertTailList(
                &g_stUdpALEAcceptPendedList,
                &pFlowContext->listEntry
                );
            wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
            ASSERT(NULL != wdfRequestQueue);
            pFlowContext->wdfWaitDnsQueryQueue = NULL;
            status = WdfIoQueueRetrieveNextRequest(
                wdfRequestQueue,
                &wdfPendedRequest
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfRequestRetrieveOutputMemory(
                wdfPendedRequest,
                &wdfOutputMemory
                );
            ASSERT(NT_SUCCESS(status));
            status = WdfMemoryCopyFromBuffer(
                wdfOutputMemory,
                0,
                pFlowContext,
                sizeof(FLOW_DATA)
                );
            ASSERT(NT_SUCCESS(status));
            WdfRequestCompleteWithInformation(
                wdfPendedRequest,
                status,
                sizeof(FLOW_DATA)
                );
            WdfObjectDelete(wdfRequestQueue);
        }
    }
    WdfObjectReleaseLock(g_wdfControlDevice);
}

void NTAPI onAleAcceptRecvV4Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    PADDRESSES_DESCRIPTOR       pAddressesDescriptor = NULL;
    UINT32                      ulRemoteAddress, ulI, ulRemoteAddressN;
    int                         i;
    BOOLEAN                     bLocalNetwork = FALSE;
    PLIST_ENTRY                 pListEntry, pFirstLE, pPrevLE, pLastLE;
    PFLOW_DATA                  pFlowContext = NULL, pFirstAcceptingFlowContext = NULL;
    UINT32                      ulInboundCount = 0;
    BOOLEAN                     bEmpty;
    PNET_BUFFER_LIST            pNetBufferList;
    NTSTATUS                    status = STATUS_SUCCESS;
    IPPROTO                     enIpProto;
    PNET_BUFFER                 pNetBuffer;
    UINT32                      nDataSize;
    UINT32                      ulUdpDataOffset;
    UINT32                      ulIpHeaderSize;
    UINT32                      ulTransportHeaderSize;
    COMPARTMENT_ID              enUdpCompartmentID;
    UINT32                      ulUdpDataLength;
    UINT16                      usRemotePort;
    HANDLE                      hCompletionHandle = NULL;
    IN_ADDR                     stIpAddress;
    WCHAR                       szIpAddress[128];
    LPWSTR                      pAddressEnd;
    FWPS_PACKET_INJECTION_STATE packetState;
    HANDLE                      hInjectionHandle;
    WDFFILEOBJECT               wdfInjectDataObject = NULL;
    BOOLEAN                     bTestIpV4;
    BOOLEAN                     bIPv6;
    WDFQUEUE                    wdfRequestQueue;
    WDFREQUEST                  wdfPendedRequest;
    WDFMEMORY                   wdfOutputMemory = NULL;
    IN6_ADDR                    stRemoteAddress;
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    pNetBufferList = (PNET_BUFFER_LIST) layerData;
    ASSERT(pNetBufferList != NULL);
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
    ASSERT(IPPROTO_UDP == enIpProto);
    ulRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32;
    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
    pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
    nDataSize = NET_BUFFER_DATA_LENGTH(pNetBuffer);
    ulUdpDataOffset = NET_BUFFER_DATA_OFFSET(pNetBuffer);
    enUdpCompartmentID = (COMPARTMENT_ID) inMetaValues->compartmentId;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE));
    ulIpHeaderSize = inMetaValues->ipHeaderSize;
    ulTransportHeaderSize = inMetaValues->transportHeaderSize;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16;
    hInjectionHandle = g_hInjectionHandleV4;
    bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
    if (bTestIpV4)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Test IpV4 Host %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
    }
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor->m_pDataArray)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (c_ulLocalHost == ulRemoteAddress)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPublicIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIpArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIpCount; i++)
        {
            if (ulRemoteAddress == pAddressesDescriptor->m_pPrivateIpArray[i])
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPublicRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPublicRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateRangeArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateRangeCount; i++)
        {
            if ((ulRemoteAddress >= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulLowValue)
                && (ulRemoteAddress <= pAddressesDescriptor->m_pPrivateRangeArray[i]._ulHighValue)
                )
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPublicSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateSubnetArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateSubnetCount; i++)
        {
            UINT32  ulAddrPart = (ulRemoteAddress & pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpMask);
            if (ulAddrPart == pAddressesDescriptor->m_pPrivateSubnetArray[i]._ulIpAddr)
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    packetState = FwpsQueryPacketInjectionState(
        hInjectionHandle,
        pNetBufferList,
        (HANDLE*) &wdfInjectDataObject
        );
    if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
    {
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host was Reinjected."
                );
        }
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if ((IPPROTO_UDP == pFlowContext->enIpProto) && (!pFlowContext->bIPv6))
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    switch (pFlowContext->enContextState)
                    {
                    case csUdpWaitPermitQuery2:
                    case csUdpPermitQuery2Done:
                        pFirstAcceptingFlowContext = pFlowContext;
                        ulInboundCount++;
                        break;
                    }
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (ulInboundCount > 0)
        {
            ASSERT(1 == ulInboundCount);
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_COMPLETION_HANDLE))
    {
        // Îòâåòíîå ñîîáùåíèå ïîøëî ïî ìàðøðóòó îòëè÷íîìó îò ìàðøðóòà DNS-çàïðîñà.
        // UDP-ïîòîê íåîõîäèìî çàêðûòü.
        //stIpAddress.S_un.S_addr = ulRemoteAddressN;
        //pAddressEnd = RtlIpv4AddressToStringW(
        //    &stIpAddress,
        //    szIpAddress
        //    );
        //TraceEvents(
        //    TRACE_LEVEL_INFORMATION,
        //    TRACE_DNSFIREWALL,
        //    "%!FUNC! line:%!LINE! %!LEVEL! FWPS_METADATA_FIELD_COMPLETION_HANDLE Not Present! Host IP = %ws; clent.port = %hu;",
        //    szIpAddress,
        //    usRemotePort
        //    );
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if ((IPPROTO_UDP == pFlowContext->enIpProto) && (!pFlowContext->bIPv6))
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (usRemotePort == pFlowContext->usRemotePort)
                        && (csUdpPermitQueryDone == pFlowContext->enContextState))
                    {
                        pFirstAcceptingFlowContext = pFlowContext;
                        ulInboundCount++;
                        break;
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pListEntry->Blink;
            }
        }
        if (0 == ulInboundCount)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Matched packet not found in \"g_stFlowedFileList\"!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowContext = pFirstAcceptingFlowContext;
        ulRemoteAddress = pFlowContext->nRemoteAddressV4;
        ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
        usRemotePort = pFlowContext->usRemotePort;
        bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
        if (bTestIpV4)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Flow Context from Test IpV4 Host %ws will Removed; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
        }
        pFlowContext->enContextState = csUdpFlowBreak;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        status = FwpsFlowRemoveContext(
            pFlowContext->flowHandle,
            FWPS_LAYER_DATAGRAM_DATA_V4,
            g_nDatagramIdV4
            );
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    }
    hCompletionHandle = inMetaValues->completionHandle;
    if (!IsListEmpty(&g_stUdpAcceptNotifyList))
    {
        ulInboundCount = 0;
        pListEntry = g_stUdpAcceptNotifyList.Blink;
        pFirstLE = g_stUdpAcceptNotifyList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    pFirstAcceptingFlowContext = pFlowContext;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (ulInboundCount > 0)
        {
            if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
            {
                stIpAddress.S_un.S_addr = ulRemoteAddressN;
                pAddressEnd = RtlIpv4AddressToStringW(
                    &stIpAddress,
                    szIpAddress
                    );
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)!",
                    szIpAddress
                    );
                pListEntry = g_stUdpAcceptNotifyList.Blink;
                pFirstLE = g_stUdpAcceptNotifyList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (!pFlowContext->bIPv6)
                    {
                        if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                                classifyOut->actionType = FWP_ACTION_BLOCK;
                                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                WdfObjectReleaseLock(g_wdfControlDevice);
                                return;
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            for (ulI = 0; ulI < g_stFirewallConfig.nBlackSubnetListLength; ulI++)
            {
                UINT32  ulAddrPart = (ulRemoteAddress & g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpMask);
                if (ulAddrPart == g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpAddr)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because is in Black List Subnet!",
                        szIpAddress
                        );
                    pListEntry = g_stUdpAcceptNotifyList.Blink;
                    pFirstLE = g_stUdpAcceptNotifyList.Flink;
                    for (;;)
                    {
                        pPrevLE = pListEntry->Blink;
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bIPv6)
                        {
                            if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4) && (usRemotePort == pFlowContext->usRemotePort))
                            {
                                switch (pFlowContext->enContextState)
                                {
                                case csUdpWaitAcceptRecv:
                                    break;
                                default:
                                    ASSERT(FALSE);
                                    classifyOut->actionType = FWP_ACTION_BLOCK;
                                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                    WdfObjectReleaseLock(g_wdfControlDevice);
                                    return;
                                }
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                        }
                        if (pListEntry == pFirstLE)
                        {
                            break;
                        }
                        pListEntry = pPrevLE;
                    }
                    classifyOut->actionType = FWP_ACTION_BLOCK;
                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                    WdfObjectReleaseLock(g_wdfControlDevice);
                    return;
                }
            }
            for (ulI = 0; ulI < g_stFirewallConfig.nBlackListLength; ulI++)
            {
                if (ulRemoteAddress == g_stFirewallConfig.aBlackListArray[ulI])
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because exist in Black List!",
                        szIpAddress
                        );
                    pListEntry = g_stUdpAcceptNotifyList.Blink;
                    pFirstLE = g_stUdpAcceptNotifyList.Flink;
                    for (;;)
                    {
                        pPrevLE = pListEntry->Blink;
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (!pFlowContext->bIPv6)
                        {
                            if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                                && (usRemotePort == pFlowContext->usRemotePort))
                            {
                                switch (pFlowContext->enContextState)
                                {
                                case csUdpWaitAcceptRecv:
                                    break;
                                default:
                                    ASSERT(FALSE);
                                    classifyOut->actionType = FWP_ACTION_BLOCK;
                                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                    WdfObjectReleaseLock(g_wdfControlDevice);
                                    return;
                                }
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                        }
                        if (pListEntry == pFirstLE)
                        {
                            break;
                        }
                        pListEntry = pPrevLE;
                    }
                    classifyOut->actionType = FWP_ACTION_BLOCK;
                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                    WdfObjectReleaseLock(g_wdfControlDevice);
                    return;
                }
            }
            pFlowContext = pFirstAcceptingFlowContext;
            switch (pFlowContext->enContextState)
            {
            case csUdpWaitAcceptRecv:
                break;
            default:
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            pFlowContext->enContextState = csUdpAcceptedRecv;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            if (bTestIpV4)
            {
                TraceEvents(
                    TRACE_LEVEL_INFORMATION,
                    TRACE_DNSFIREWALL,
                    "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEFlowEstablishList\"."
                    );
            }
            pFlowContext->enFlowDataOwner = foUdpALEFlowEstablishList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stUdpALEFlowEstablishList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    if (IsListEmpty(&g_stUdpALEAcceptRecvList))
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stUdpALEAcceptRecvList\" is Empty! Host IP = %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    ulInboundCount = 0;
    pListEntry = g_stUdpALEAcceptRecvList.Blink;
    pFirstLE = g_stUdpALEAcceptRecvList.Flink;
    for (;;)
    {
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        if (!pFlowContext->bIPv6)
        {
            if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                && (usRemotePort == pFlowContext->usRemotePort))
            {
                pFirstAcceptingFlowContext = pFlowContext;
                ulInboundCount++;
            }
        }
        if (pListEntry == pFirstLE)
        {
            break;
        }
        pListEntry = pListEntry->Blink;
    }
    if (0 == ulInboundCount)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Matched element in \"g_stUdpALEAcceptRecvList\" not Found!!"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
    {
        stIpAddress.S_un.S_addr = ulRemoteAddressN;
        pAddressEnd = RtlIpv4AddressToStringW(
            &stIpAddress,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_WARNING,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)!",
            szIpAddress
            );
        pListEntry = g_stUdpALEAcceptRecvList.Blink;
        pFirstLE = g_stUdpALEAcceptRecvList.Flink;
        for (;;)
        {
            pPrevLE = pListEntry->Blink;
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (!pFlowContext->bIPv6)
            {
                if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    switch (pFlowContext->enContextState)
                    {
                    case csUdpWaitAcceptRecv:
                        break;
                    default:
                        ASSERT(FALSE);
                        classifyOut->actionType = FWP_ACTION_BLOCK;
                        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                        WdfObjectReleaseLock(g_wdfControlDevice);
                        return;
                    }
                    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                    pFlowContext->bUdpNotifyQuery = FALSE;
                    pFlowContext->enContextState = csWaitQueryStarted;
                    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                    pFlowContext->enFlowDataOwner = foAcceptableList;
                    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                    InsertTailList(
                        &g_stAcceptableList,
                        &pFlowContext->listEntry
                        );
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pPrevLE;
        }
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackSubnetListLength; ulI++)
    {
        UINT32  ulAddrPart = (ulRemoteAddress & g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpMask);
        if (ulAddrPart == g_stFirewallConfig.aBlackSubnetList[ulI]._ulIpAddr)
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because is in Black List Subnet!",
                szIpAddress
                );
            pListEntry = g_stUdpALEAcceptRecvList.Blink;
            pFirstLE = g_stUdpALEAcceptRecvList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4) && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitAcceptRecv:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackListLength; ulI++)
    {
        if (ulRemoteAddress == g_stFirewallConfig.aBlackListArray[ulI])
        {
            stIpAddress.S_un.S_addr = ulRemoteAddressN;
            pAddressEnd = RtlIpv4AddressToStringW(
                &stIpAddress,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Host %ws Blocked because exist in Black List!",
                szIpAddress
                );
            pListEntry = g_stUdpALEAcceptRecvList.Blink;
            pFirstLE = g_stUdpALEAcceptRecvList.Flink;
            for (;;)
            {
                pPrevLE = pListEntry->Blink;
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bIPv6)
                {
                    if ((ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                        && (usRemotePort == pFlowContext->usRemotePort))
                    {
                        switch (pFlowContext->enContextState)
                        {
                        case csUdpWaitAcceptRecv:
                            break;
                        default:
                            ASSERT(FALSE);
                            classifyOut->actionType = FWP_ACTION_BLOCK;
                            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                            WdfObjectReleaseLock(g_wdfControlDevice);
                            return;
                        }
                        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                        pFlowContext->bUdpNotifyQuery = FALSE;
                        pFlowContext->enContextState = csWaitQueryStarted;
                        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                        pFlowContext->enFlowDataOwner = foAcceptableList;
                        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                        InsertTailList(
                            &g_stAcceptableList,
                            &pFlowContext->listEntry
                            );
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pPrevLE;
            }
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    ulInboundCount = 0;
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if ((IPPROTO_UDP == pFlowContext->enIpProto) && (!pFlowContext->bIPv6))
            {
                if (ulRemoteAddress == pFlowContext->nRemoteAddressV4)
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    pFlowContext = pFirstAcceptingFlowContext;
    switch (pFlowContext->enContextState)
    {
    case csUdpWaitAcceptRecv:
        break;
    default:
        ASSERT(FALSE);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
    if (0 == ulInboundCount)
    {
        pFlowContext->enContextState = csUdpAcceptedRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        if (bTestIpV4)
        {
            TraceEvents(
                TRACE_LEVEL_INFORMATION,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEFlowEstablishList\"."
                );
        }
        pFlowContext->enFlowDataOwner = foUdpALEFlowEstablishList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEFlowEstablishList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pFlowContext->pUdpQueryBufferList = pNetBufferList;
    pFlowContext->ulUdpQueryBufferSize = nDataSize + ulIpHeaderSize + ulTransportHeaderSize;
    pFlowContext->ulUdpQueryDataOffset = ulUdpDataOffset;
    pFlowContext->ulUdpQueryPacketOffset = ulUdpDataOffset - ulIpHeaderSize - ulTransportHeaderSize;
    ulUdpDataLength = nDataSize;
    pFlowContext->ulUdpQueryDataLength = ulUdpDataLength;
    ASSERT(pFlowContext->ulUdpQueryDataLength > 0);
    pFlowContext->enUdpQueryCompartmentID = enUdpCompartmentID;
    pFlowContext->ulUdpQueryIpHeaderSize = ulIpHeaderSize;
    pFlowContext->ulUdpQueryTransportHeaderSize = ulTransportHeaderSize;
    FwpsReferenceNetBufferList(
        pNetBufferList,
        TRUE
        );
    pFlowContext->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX].value.uint32;
    pFlowContext->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX].value.uint32;
    pFlowContext->hAleAuthRecvAcceptCompletionHandle = hCompletionHandle;
    status = FwpsPendOperation(
        hCompletionHandle,
        &pFlowContext->hAleAuthRecvAcceptContext
        );
    ASSERT(NT_SUCCESS(status));
    pFlowContext->bUdpQueryClassifyPended = FALSE;
    pFlowContext->enContextState = csUdpFlowEstablishPended;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    if (bTestIpV4)
    {
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Packet from Tested IpV4 Host Insert to \"g_stUdpALEAcceptPendedList\"."
            );
    }
    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stUdpALEAcceptPendedList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    WdfObjectReleaseLock(g_wdfControlDevice);
}

void NTAPI onAleAcceptRecvV6Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __inout FWPS_CLASSIFY_OUT* classifyOut
    )
{
    PADDRESSES_DESCRIPTOR       pAddressesDescriptor = NULL;
    UINT32                      ulI;
    int                         i;
    BOOLEAN                     bLocalNetwork = FALSE;
    PLIST_ENTRY                 pListEntry, pFirstLE, pLastLE, pPrevLE;
    PFLOW_DATA                  pFlowContext = NULL, pFirstAcceptingFlowContext = NULL;
    UINT32                      ulInboundCount = 0;
    BOOLEAN                     bEmpty;
    PNET_BUFFER_LIST            pNetBufferList;
    NTSTATUS                    status = STATUS_SUCCESS;
    IPPROTO                     enIpProto;
    PNET_BUFFER                 pNetBuffer;
    UINT32                      nDataSize;
    UINT32                      ulUdpDataOffset;
    UINT32                      ulIpHeaderSize;
    UINT32                      ulTransportHeaderSize;
    COMPARTMENT_ID              enUdpCompartmentID;
    UINT32                      ulUdpDataLength;
    UINT16                      usRemotePort;
    FWP_BYTE_ARRAY16            *pRemoteAddress;
    HANDLE                      hCompletionHandle = NULL;
    IN6_ADDR                    stIp6Address;
    WCHAR                       szIpAddress[128];
    LPWSTR                      pAddressEnd;
    FWPS_PACKET_INJECTION_STATE packetState;
    HANDLE                      hInjectionHandle;
    WDFFILEOBJECT               wdfInjectDataObject = NULL;
    BOOLEAN                     bTestIpV4;
    BOOLEAN                     bIPv6;
    WDFQUEUE                    wdfRequestQueue;
    WDFREQUEST                  wdfPendedRequest;
    WDFMEMORY                   wdfOutputMemory = NULL;
    IN_ADDR                     stIpAddress;
    IN6_ADDR                    stRemoteAddress;
    UINT32                      ulRemoteAddress = 0, ulRemoteAddressN = 0;
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        return;
    }
    WdfObjectAcquireLock(g_wdfControlDevice);
    pNetBufferList = (PNET_BUFFER_LIST) layerData;
    ASSERT(pNetBufferList != NULL);
    enIpProto = (IPPROTO) inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
    ASSERT(IPPROTO_UDP == enIpProto);
    pRemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS].value.byteArray16;
    pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
    nDataSize = NET_BUFFER_DATA_LENGTH(pNetBuffer);
    ulUdpDataOffset = NET_BUFFER_DATA_OFFSET(pNetBuffer);
    enUdpCompartmentID = (COMPARTMENT_ID) inMetaValues->compartmentId;
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE));
    ulIpHeaderSize = inMetaValues->ipHeaderSize;
    ulTransportHeaderSize = inMetaValues->transportHeaderSize;
    usRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT].value.uint16;
    hInjectionHandle = g_hInjectionHandleV6;
    pAddressesDescriptor = WdfObjectGetTypedContext(
        g_wdfControlDevice,
        ADDRESSES_DESCRIPTOR
        );
    if (NULL == pAddressesDescriptor)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL == pAddressesDescriptor->m_pDataArray)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pAddressesDescriptor->m_pDataArray)"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!bfIPv6AddressInIPv6Subnet(pRemoteAddress, c_pGlobalIPv6Subnet))
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPublicIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPublicIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPublicIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (NULL != pAddressesDescriptor->m_pPrivateIPV6AddrArray)
    {
        for (i = 0; i<pAddressesDescriptor->m_nPrivateIPV6AddrCount; i++)
        {
            if (bfIPv6AddressInIPv6Subnet(pRemoteAddress, &pAddressesDescriptor->m_pPrivateIPV6AddrArray[i]))
            {
                bLocalNetwork = TRUE;
                break;
            }
        }
    }
    if (bLocalNetwork)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    packetState = FwpsQueryPacketInjectionState(
        hInjectionHandle,
        pNetBufferList,
        (HANDLE*) &wdfInjectDataObject
        );
    if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if ((IPPROTO_UDP == pFlowContext->enIpProto) && pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    switch (pFlowContext->enContextState)
                    {
                    case csUdpWaitPermitQuery2:
                    case csUdpPermitQuery2Done:
                        pFirstAcceptingFlowContext = pFlowContext;
                        ulInboundCount++;
                        break;
                    }
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (ulInboundCount > 0)
        {
            ASSERT(1 == ulInboundCount);
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_COMPLETION_HANDLE))
    {
        // Îòâåòíîå ñîîáùåíèå ïîøëî ïî ìàðøðóòó îòëè÷íîìó îò ìàðøðóòà DNS-çàïðîñà.
        // UDP-ïîòîê íåîõîäèìî çàêðûòü.
        //RtlCopyMemory(
        //    &stIp6Address,
        //    pRemoteAddress,
        //    sizeof(stIp6Address)
        //    );
        //pAddressEnd = RtlIpv6AddressToStringW(
        //    &stIp6Address,
        //    szIpAddress
        //    );
        //TraceEvents(
        //    TRACE_LEVEL_WARNING,
        //    TRACE_DNSFIREWALL,
        //    "%!FUNC! line:%!LINE! %!LEVEL! FWPS_METADATA_FIELD_COMPLETION_HANDLE Not Present! Host IP = %ws; clent.port = %hu;",
        //    szIpAddress,
        //    usRemotePort
        //    );
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stFlowedFileList))
        {
            pListEntry = g_stFlowedFileList.Blink;
            pFirstLE = g_stFlowedFileList.Flink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if ((IPPROTO_UDP == pFlowContext->enIpProto) && (pFlowContext->bIPv6))
                {
                    if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                        && (usRemotePort == pFlowContext->usRemotePort)
                        && (csUdpPermitQueryDone == pFlowContext->enContextState))
                    {
                        pFirstAcceptingFlowContext = pFlowContext;
                        ulInboundCount++;
                        break;
                    }
                }
                if (pListEntry == pFirstLE)
                {
                    break;
                }
                pListEntry = pListEntry->Blink;
            }
        }
        if (0 == ulInboundCount)
        {
            RtlCopyMemory(
                &stIp6Address,
                pRemoteAddress,
                sizeof(stIp6Address)
                );
            pAddressEnd = RtlIpv6AddressToStringW(
                &stIp6Address,
                szIpAddress
                );
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! Matched packet not found in \"g_stFlowedFileList\"!! Host %ws; clent.port = %hu;",
                szIpAddress,
                usRemotePort
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        ulInboundCount = 0;
        if (!IsListEmpty(&g_stUdpALEAcceptPendedList))
        {
            pListEntry = g_stUdpALEAcceptPendedList.Flink;
            pLastLE = g_stUdpALEAcceptPendedList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (ulInboundCount > 0)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Read Pended Accepted Packet fom Test IpV4 Host %ws; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                //ASSERT(FALSE);
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        if ((0 == ulInboundCount) && (!IsListEmpty(&g_stUdpInboundList)))
        {
            pListEntry = g_stUdpInboundList.Flink;
            pLastLE = g_stUdpInboundList.Blink;
            for (;;)
            {
                pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                ASSERT(pFlowContext == pFlowContext->pThis);
                if (!pFlowContext->bUdpQueryClassifyPended)
                {
                    ulInboundCount++;
                    break;
                }
                if (pListEntry == pLastLE)
                {
                    break;
                }
                pListEntry = pListEntry->Flink;
            }
            if (1 == ulInboundCount)
            {
                bIPv6 = pFlowContext->bIPv6;
                if (bIPv6)
                {
                    RtlCopyMemory(
                        &stRemoteAddress,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stRemoteAddress)
                        );
                }
                else
                {
                    ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                    ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                }
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = ((!bIPv6) && (c_ulTestIpV4 == ulRemoteAddress));
                if (bTestIpV4)
                {
                    stIpAddress.S_un.S_addr = ulRemoteAddressN;
                    pAddressEnd = RtlIpv4AddressToStringW(
                        &stIpAddress,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNSFIREWALL,
                        "%!FUNC! line:%!LINE! %!LEVEL! Pended Inbound Packet from Test IpV4 Host %ws Insert to \"g_stUdpALEAcceptPendedList\"; clent.port = %hu;",
                        szIpAddress,
                        usRemotePort
                        );
                }
                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                ulRemoteAddress = pFlowContext->nRemoteAddressV4;
                ulRemoteAddressN = RtlUlongByteSwap(ulRemoteAddress);
                usRemotePort = pFlowContext->usRemotePort;
                bTestIpV4 = (c_ulTestIpV4 == ulRemoteAddress);
                pFlowContext->bUdpQueryClassifyPended = TRUE;
                pFlowContext->hAleAuthRecvAcceptCompletionHandle = NULL;
                pFlowContext->ulUdpQueryCount++;
                pFlowContext->pUdpQueryBufferList = pFlowContext->pUdpQuery2BufferList;
                pFlowContext->pUdpQuery2BufferList = NULL;
                pFlowContext->ulUdpQueryBufferSize = pFlowContext->ulUdpQuery2BufferSize;
                pFlowContext->ulUdpQuery2BufferSize = 0;
                pFlowContext->ulUdpQueryDataOffset = pFlowContext->ulUdpQuery2DataOffset;
                pFlowContext->ulUdpQuery2DataOffset = 0;
                pFlowContext->ulUdpQueryPacketOffset = pFlowContext->ulUdpQuery2PacketOffset;
                pFlowContext->ulUdpQuery2PacketOffset = 0;
                pFlowContext->ulUdpQueryDataLength = pFlowContext->ulUdpQuery2DataLength;
                pFlowContext->ulUdpQuery2DataLength = 0;
                pFlowContext->enUdpQueryCompartmentID = pFlowContext->enUdpQuery2CompartmentID;
                pFlowContext->enUdpQuery2CompartmentID = (COMPARTMENT_ID) 0;
                pFlowContext->ulUdpQueryIpHeaderSize = pFlowContext->ulUdpQuery2IpHeaderSize;
                pFlowContext->ulUdpQuery2IpHeaderSize = 0;
                pFlowContext->ulUdpQueryTransportHeaderSize = pFlowContext->ulUdpQuery2TransportHeaderSize;
                pFlowContext->ulUdpQuery2TransportHeaderSize = 0;
                pFlowContext->enContextState = csUdpWaitReadQuery;
                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                //ASSERT(FALSE);
                InsertTailList(
                    &g_stUdpALEAcceptPendedList,
                    &pFlowContext->listEntry
                    );
                wdfRequestQueue = pFlowContext->wdfWaitDnsQueryQueue;
                ASSERT(NULL != wdfRequestQueue);
                pFlowContext->wdfWaitDnsQueryQueue = NULL;
                status = WdfIoQueueRetrieveNextRequest(
                    wdfRequestQueue,
                    &wdfPendedRequest
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfRequestRetrieveOutputMemory(
                    wdfPendedRequest,
                    &wdfOutputMemory
                    );
                ASSERT(NT_SUCCESS(status));
                status = WdfMemoryCopyFromBuffer(
                    wdfOutputMemory,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA)
                    );
                ASSERT(NT_SUCCESS(status));
                WdfRequestCompleteWithInformation(
                    wdfPendedRequest,
                    status,
                    sizeof(FLOW_DATA)
                    );
                WdfObjectDelete(wdfRequestQueue);
            }
        }
        pFlowContext = pFirstAcceptingFlowContext;
        pFlowContext->enContextState = csUdpFlowBreak;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        status = FwpsFlowRemoveContext(
            pFlowContext->flowHandle,
            FWPS_LAYER_DATAGRAM_DATA_V6,
            g_nDatagramIdV6
            );
        if (!NT_SUCCESS(status))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNSFIREWALL,
                "%!FUNC! line:%!LINE! %!LEVEL! \"FwpsFlowRemoveContext\" return %!STATUS!",
                status
                );
        }
        return;
    }
    hCompletionHandle = inMetaValues->completionHandle;
    if (!IsListEmpty(&g_stUdpAcceptNotifyList))
    {
        ulInboundCount = 0;
        pListEntry = g_stUdpAcceptNotifyList.Blink;
        pFirstLE = g_stUdpAcceptNotifyList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if (pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                    && (usRemotePort == pFlowContext->usRemotePort))
                {
                    pFirstAcceptingFlowContext = pFlowContext;
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
        if (ulInboundCount > 0)
        {
            if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
            {
                pListEntry = g_stUdpAcceptNotifyList.Blink;
                pFirstLE = g_stUdpAcceptNotifyList.Flink;
                for (;;)
                {
                    pPrevLE = pListEntry->Blink;
                    pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                    ASSERT(pFlowContext == pFlowContext->pThis);
                    if (pFlowContext->bIPv6)
                    {
                        if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                            && (usRemotePort == pFlowContext->usRemotePort))
                        {
                            switch (pFlowContext->enContextState)
                            {
                            case csUdpWaitAcceptRecv:
                                break;
                            default:
                                ASSERT(FALSE);
                                classifyOut->actionType = FWP_ACTION_BLOCK;
                                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                WdfObjectReleaseLock(g_wdfControlDevice);
                                return;
                            }
                            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                            pFlowContext->bIPv6 = FALSE;
                            pFlowContext->bUdpNotifyQuery = FALSE;
                            pFlowContext->enContextState = csWaitQueryStarted;
                            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                            pFlowContext->enFlowDataOwner = foAcceptableList;
                            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                            InsertTailList(
                                &g_stAcceptableList,
                                &pFlowContext->listEntry
                                );
                        }
                    }
                    if (pListEntry == pFirstLE)
                    {
                        break;
                    }
                    pListEntry = pPrevLE;
                }
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            for (ulI = 0; ulI < g_stFirewallConfig.nBlackListV6Length; ulI++)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &g_stFirewallConfig.aBlackListV6Array[ulI]))
                {
                    pListEntry = g_stUdpAcceptNotifyList.Blink;
                    pFirstLE = g_stUdpAcceptNotifyList.Flink;
                    for (;;)
                    {
                        pPrevLE = pListEntry->Blink;
                        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
                        ASSERT(pFlowContext == pFlowContext->pThis);
                        if (pFlowContext->bIPv6)
                        {
                            if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                                && (usRemotePort == pFlowContext->usRemotePort))
                            {
                                switch (pFlowContext->enContextState)
                                {
                                case csUdpWaitAcceptRecv:
                                    break;
                                default:
                                    ASSERT(FALSE);
                                    classifyOut->actionType = FWP_ACTION_BLOCK;
                                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                                    WdfObjectReleaseLock(g_wdfControlDevice);
                                    return;
                                }
                                bEmpty = RemoveEntryList(&pFlowContext->listEntry);
                                pFlowContext->bIPv6 = FALSE;
                                pFlowContext->bUdpNotifyQuery = FALSE;
                                pFlowContext->enContextState = csWaitQueryStarted;
                                push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
                                pFlowContext->enFlowDataOwner = foAcceptableList;
                                push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
                                InsertTailList(
                                    &g_stAcceptableList,
                                    &pFlowContext->listEntry
                                    );
                            }
                        }
                        if (pListEntry == pFirstLE)
                        {
                            break;
                        }
                        pListEntry = pPrevLE;
                    }
                    classifyOut->actionType = FWP_ACTION_BLOCK;
                    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                    WdfObjectReleaseLock(g_wdfControlDevice);
                    return;
                }
            }
            pFlowContext = pFirstAcceptingFlowContext;
            switch (pFlowContext->enContextState)
            {
            case csUdpWaitAcceptRecv:
                break;
            default:
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            pFlowContext->enContextState = csUdpAcceptedRecv;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foUdpALEFlowEstablishList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stUdpALEFlowEstablishList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_PERMIT;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    if (IsListEmpty(&g_stUdpALEAcceptRecvList))
    {
        RtlCopyMemory(
            &stIp6Address,
            pRemoteAddress,
            sizeof(stIp6Address)
            );
        pAddressEnd = RtlIpv6AddressToStringW(
            &stIp6Address,
            szIpAddress
            );
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! \"g_stUdpALEAcceptRecvList\" is Empty! Host IP = %ws; clent.port = %hu;",
            szIpAddress,
            usRemotePort
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    ulInboundCount = 0;
    pListEntry = g_stUdpALEAcceptRecvList.Blink;
    pFirstLE = g_stUdpALEAcceptRecvList.Flink;
    for (;;)
    {
        pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
        ASSERT(pFlowContext == pFlowContext->pThis);
        if (pFlowContext->bIPv6)
        {
            if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6)
                && (usRemotePort == pFlowContext->usRemotePort))
            {
                pFirstAcceptingFlowContext = pFlowContext;
                ulInboundCount++;
            }
        }
        if (pListEntry == pFirstLE)
        {
            break;
        }
        pListEntry = pListEntry->Blink;
    }
    if (0 == ulInboundCount)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNSFIREWALL,
            "%!FUNC! line:%!LINE! %!LEVEL! Matched element in \"g_stUdpALEAcceptRecvList\" not Found!!"
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    if (g_bFiltersChangeInProgress | g_stFirewallConfig.bExternalClientBlocked)
    {
        pFlowContext = pFirstAcceptingFlowContext;
        switch (pFlowContext->enContextState)
        {
        case csUdpWaitAcceptRecv:
            break;
        default:
            ASSERT(FALSE);
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
        bEmpty = RemoveEntryList(&pFlowContext->listEntry);
        pFlowContext->bUdpNotifyQuery = FALSE;
        pFlowContext->bIPv6 = FALSE;
        pFlowContext->enContextState = csWaitQueryStarted;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        pFlowContext->enFlowDataOwner = foAcceptableList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stAcceptableList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    for (ulI = 0; ulI < g_stFirewallConfig.nBlackListV6Length; ulI++)
    {
        if (bfIsIPv6AddressesEqual(pRemoteAddress, &g_stFirewallConfig.aBlackListV6Array[ulI]))
        {
            pFlowContext = pFirstAcceptingFlowContext;
            switch (pFlowContext->enContextState)
            {
            case csUdpWaitAcceptRecv:
                break;
            default:
                ASSERT(FALSE);
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                WdfObjectReleaseLock(g_wdfControlDevice);
                return;
            }
            bEmpty = RemoveEntryList(&pFlowContext->listEntry);
            pFlowContext->bIPv6 = FALSE;
            pFlowContext->bUdpNotifyQuery = FALSE;
            pFlowContext->enContextState = csWaitQueryStarted;
            push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
            pFlowContext->enFlowDataOwner = foAcceptableList;
            push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
            InsertTailList(
                &g_stAcceptableList,
                &pFlowContext->listEntry
                );
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            WdfObjectReleaseLock(g_wdfControlDevice);
            return;
        }
    }
    ulInboundCount = 0;
    if (!IsListEmpty(&g_stFlowedFileList))
    {
        pListEntry = g_stFlowedFileList.Blink;
        pFirstLE = g_stFlowedFileList.Flink;
        for (;;)
        {
            pFlowContext = CONTAINING_RECORD(pListEntry, FLOW_DATA, listEntry);
            ASSERT(pFlowContext == pFlowContext->pThis);
            if ((IPPROTO_UDP == pFlowContext->enIpProto) && pFlowContext->bIPv6)
            {
                if (bfIsIPv6AddressesEqual(pRemoteAddress, &pFlowContext->stRemoteAddressV6))
                {
                    ulInboundCount++;
                }
            }
            if (pListEntry == pFirstLE)
            {
                break;
            }
            pListEntry = pListEntry->Blink;
        }
    }
    pFlowContext = pFirstAcceptingFlowContext;
    switch (pFlowContext->enContextState)
    {
    case csUdpWaitAcceptRecv:
        break;
    default:
        ASSERT(FALSE);
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    bEmpty = RemoveEntryList(&pFlowContext->listEntry);
    if (0 == ulInboundCount)
    {
        pFlowContext->enContextState = csUdpAcceptedRecv;
        push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
        pFlowContext->enFlowDataOwner = foUdpALEFlowEstablishList;
        push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
        InsertTailList(
            &g_stUdpALEFlowEstablishList,
            &pFlowContext->listEntry
            );
        classifyOut->actionType = FWP_ACTION_PERMIT;
        WdfObjectReleaseLock(g_wdfControlDevice);
        return;
    }
    pFlowContext->pUdpQueryBufferList = pNetBufferList;
    pFlowContext->ulUdpQueryBufferSize = nDataSize + ulIpHeaderSize + ulTransportHeaderSize;
    pFlowContext->ulUdpQueryDataOffset = ulUdpDataOffset;
    pFlowContext->ulUdpQueryPacketOffset = ulUdpDataOffset - ulIpHeaderSize - ulTransportHeaderSize;
    ulUdpDataLength = nDataSize;
    pFlowContext->ulUdpQueryDataLength = ulUdpDataLength;
    ASSERT(pFlowContext->ulUdpQueryDataLength > 0);
    pFlowContext->enUdpQueryCompartmentID = enUdpCompartmentID;
    pFlowContext->ulUdpQueryIpHeaderSize = ulIpHeaderSize;
    pFlowContext->ulUdpQueryTransportHeaderSize = ulTransportHeaderSize;
    FwpsReferenceNetBufferList(
        pNetBufferList,
        TRUE
        );
    pFlowContext->interfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_INTERFACE_INDEX].value.uint32;
    pFlowContext->subInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_SUB_INTERFACE_INDEX].value.uint32;
    pFlowContext->hAleAuthRecvAcceptCompletionHandle = hCompletionHandle;
    status = FwpsPendOperation(
        hCompletionHandle,
        &pFlowContext->hAleAuthRecvAcceptContext
        );
    ASSERT(NT_SUCCESS(status));
    pFlowContext->bUdpQueryClassifyPended = FALSE;
    pFlowContext->enContextState = csUdpFlowEstablishPended;
    push_css(pFlowContext->arContextStateStack, pFlowContext->enContextState);
    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    pFlowContext->enFlowDataOwner = foUdpALEAcceptPendedList;
    push_fos(pFlowContext->arFlowDataOwnerStack, pFlowContext->enFlowDataOwner);
    InsertTailList(
        &g_stUdpALEAcceptPendedList,
        &pFlowContext->listEntry
        );
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    WdfObjectReleaseLock(g_wdfControlDevice);
}
