Exemple #1
0
    void right_justify_output(unsigned long _right_justified_offset, unsigned long _max_length, unsigned long _value) throw()
    {
        static const unsigned long CoversionBufferLength = 12;
        wchar_t ConversionBuffer[CoversionBufferLength];

        ctl::ctFatalCondition(
            _right_justified_offset > OutputBufferSize,
            L"ctsStatusInformation will only print up to %u columns - an offset of %u was given",
            OutputBufferSize, _right_justified_offset);
        _Analysis_assume_(_right_justified_offset <= OutputBufferSize);

        ctl::ctFatalCondition(
            _max_length > CoversionBufferLength - 1, // minus one for the null terminator
            L"ctsStatusInformation will only print converted strings up to %u characters long - the number '%u' was given",
            CoversionBufferLength - 1, _max_length);
        _Analysis_assume_(_max_length > CoversionBufferLength - 1);

        int converted = ::_snwprintf_s(
                            ConversionBuffer,
                            CoversionBufferLength,
                            _TRUNCATE,
                            L"%u",
                            _value);
        ctl::ctFatalCondition(
            -1 == converted,
            L"_snwprintf_s failed (value == %u), errno == %d",
            _value, errno);
        _Analysis_assume_(converted != -1);

        ::wmemcpy_s(
            OutputBuffer + (_right_justified_offset - converted),
            OutputBufferSize - (_right_justified_offset - converted),
            ConversionBuffer,
            converted);
    }
_Use_decl_annotations_
VOID
RXReceiveIndicateWorkItem(
        PVOID  WorkItemContext,
        NDIS_HANDLE NdisIoWorkItemHandle)
/*++

Routine Description:

    Work Item function for Receive Indication. The work item is invoked if the corresponding receive
    DPC has run enough times on the processor without a transition to PASSIVE to risk hitting the DPC
    watchdog timer.

    Runs at IRQL = PASSIVE_LEVEL.

Arguments:

    WorkItemContext                     PMP_ADAPTER_RECEIVE_DPC structure for the corresponding receive DPC
    NdisIoWorkItemHandle                Workitem handle, unused

Return Value:

    None.

--*/
{
    PMP_ADAPTER_RECEIVE_DPC AdapterDpc = (PMP_ADAPTER_RECEIVE_DPC)WorkItemContext;
    UNREFERENCED_PARAMETER(NdisIoWorkItemHandle);
	ASSERT(AdapterDpc != NULL);
	_Analysis_assume_(AdapterDpc != NULL);
    RXReceiveIndicate(AdapterDpc->Adapter, AdapterDpc, FALSE);
}
Exemple #3
0
VOID
RamDiskEvtIoWrite(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t Length
    )

/*++

Routine Description:

    This event is invoked when the framework receives IRP_MJ_WRITE request.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length - Length of the data buffer associated with the request.
             The default property of the queue is to not dispatch
             zero length read & write requests to the driver and
             complete is with status success. So we will never get
             a zero length request.

Return Value:

    VOID

--*/
{
    PDEVICE_EXTENSION      devExt = QueueGetExtension(Queue)->DeviceExtension;
    NTSTATUS               Status = STATUS_INVALID_PARAMETER;
    WDF_REQUEST_PARAMETERS Parameters;
    LARGE_INTEGER          ByteOffset;
    WDFMEMORY              hMemory;

    _Analysis_assume_(Length > 0);

    WDF_REQUEST_PARAMETERS_INIT(&Parameters);
    WdfRequestGetParameters(Request, &Parameters);

    ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;

    if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {

        Status = WdfRequestRetrieveInputMemory(Request, &hMemory);
        if(NT_SUCCESS(Status)){

            Status = WdfMemoryCopyToBuffer(hMemory, // Source
                                    0,              // offset in Source memory where the copy has to start
                                    devExt->DiskImage + ByteOffset.LowPart, // destination
                                    Length);
        }

    }

    WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
}
NTSTATUS
ClassGlobalDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
)

{
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    // Code Analysis cannot analyze the code paths specific to clients.
    _Analysis_assume_(FALSE);
    return (commonExtension->DispatchTable[irpStack->MajorFunction])(DeviceObject, Irp);

}
static void phHciNfc_HciCoreLowerLayerSendCb(void *pContext, NFCSTATUS wStatus,void *pInfo)
{
    phNfc_sData_t tSendData;
    uint8_t  aHcpFragmentData[PHHCI_HCP_MAX_PACKET_SIZE];
    uint32_t dwTotalLenOfBuiltPkt = 0;
    PHNFC_UNUSED_VARIABLE(pInfo); /* No Data Expected from lower Layer */
    if(pContext != NULL)
    {
        phHciNfc_HciContext_t *pHciContext = (phHciNfc_HciContext_t *) pContext;
        if(wStatus == NFCSTATUS_SUCCESS)
        {
            wStatus = phHciNfc_HciCoreCheckBuildHciFragments(pHciContext,
                                                             wStatus,
                                                             &dwTotalLenOfBuiltPkt,
                                                             (uint8_t*)&aHcpFragmentData);

            _Analysis_assume_(dwTotalLenOfBuiltPkt <= PHHCI_HCP_MAX_PACKET_SIZE);
        }else
        {
            /* Failed Response from Lower Layer */
            PH_LOG_LIBNFC_CRIT_STR(" Failed /Pending Response from Lower Layer ");

            /* Intimate the upper layer */
            pHciContext->pHciCoreContext.phHciNfcCoreUpperLayerSendCb(pHciContext->pHciCoreContext.pUpperLayerContext,
                                                                      wStatus);
        }
        /* Send the built HCI packets to Lower Layer */
        if(dwTotalLenOfBuiltPkt > 0)
        {
            tSendData.length = dwTotalLenOfBuiltPkt;
            tSendData.buffer = aHcpFragmentData;
            wStatus = phNciNfc_SeSendData(pHciContext->pNciContext,
                                        pHciContext->pSeHandle,
                                        &phHciNfc_HciCoreLowerLayerSendCb,
                                        pHciContext,
                                        &tSendData);
            if(wStatus == NFCSTATUS_PENDING)
            {
                PH_LOG_LIBNFC_CRIT_STR(" HCP Packet Sent to NCI ");
            }
            else
            {
                PH_LOG_LIBNFC_CRIT_STR(" Failed to send HCP to Lower ");
            }
        }
    }else
    {
        PH_LOG_LIBNFC_CRIT_STR(" Invalid HCI Context received from Lower Layer ");
    }
}
NTSTATUS
SerenumSyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
                      IN PVOID Context)
{
    PKEVENT SerenumSyncEvent = (PKEVENT) Context;

    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Irp);

    _Analysis_assume_(SerenumSyncEvent != NULL);

    KeSetEvent(SerenumSyncEvent, IO_NO_INCREMENT, FALSE);
    return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
RXReceiveIndicateDpc(
    _In_ struct _KDPC  *Dpc,
    _In_opt_ PVOID  DeferredContext,
    _In_opt_ PVOID  SystemArgument1,
    _In_opt_ PVOID  SystemArgument2)
/*++

Routine Description:

    DPC function for Receive Indication. Please note that receive
    timer DPC is not required when you are talking to a real device. In real
    miniports, this DPC is usually provided by NDIS as MPHandleInterrupt
    callback whenever the device interrupts for receive indication.

Arguments:

    DeferredContext             Pointer to our adapter
    SystemArgument1             PMP_ADAPTER_RECEIVE_DPC structure for this DPC

Return Value:

    None.

--*/
{

    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(SystemArgument2);

    ASSERT(DeferredContext != NULL);
    ASSERT(SystemArgument1 != NULL);
    _Analysis_assume_(DeferredContext != NULL);
    _Analysis_assume_(SystemArgument1 != NULL);

    RXReceiveIndicate((PMP_ADAPTER)DeferredContext, (PMP_ADAPTER_RECEIVE_DPC)SystemArgument1, TRUE);
}
Exemple #8
0
VOID
SimTcEngagePassiveCooling (
    _Inout_opt_ PVOID Context,
    _In_        ULONG Percentage
    )

/*++

Routine Description:

    SimTcEngagePassiveCooling is called by the device's clients to set the
    device's passive cooling state.

Arguments:

    Context - Supplies a handle to the target device.

    Percentage - Supplies the new thermal level in percent.

Return Value:

    None

--*/

{
    PFDO_DATA DevExt;
    ULONG PreviousThermalLevel;

    DebugEnter();
    PAGED_CODE();

    _Analysis_assume_(Context != NULL);
    NT_ASSERT(Context != NULL);
    DevExt = GetDeviceExtension((WDFDEVICE)Context);

    PreviousThermalLevel = DevExt->ThermalLevel;
    DevExt->ThermalLevel = Percentage;

    DebugPrint(SIMTC_TRACE,
               "Thermal level was %lu, now %lu.\n",
               PreviousThermalLevel,
               Percentage);

    DebugExit();
}
Exemple #9
0
VOID
SimTcEngageActiveCooling(
    _Inout_opt_ PVOID Context,
    _In_        BOOLEAN Engaged
    )

/*++

Routine Description:

    SimTcEngageActiveCooling is called by the device's clients to set the
    device's active cooling state.

Arguments:

    Context - Supplies a handle to the target device.

    Engaged - Supplies the new cooling state.

Return Value:

    None

--*/

{
    PFDO_DATA DevExt;
    BOOLEAN PreviousActiveCoolingState;

    DebugEnter();
    PAGED_CODE();

    _Analysis_assume_(Context != NULL);
    NT_ASSERT(Context != NULL);
    DevExt = GetDeviceExtension((WDFDEVICE)Context);

    PreviousActiveCoolingState = DevExt->ActiveCoolingEngaged;
    DevExt->ActiveCoolingEngaged = Engaged;

    DebugPrint(SIMTC_TRACE,
               "Active cooling state was %s, now %s.\n",
               (PreviousActiveCoolingState != FALSE) ? "on" : "off",
               (Engaged != FALSE) ? "on" : "off");

    DebugExit();
}
Exemple #10
0
VOID TransferPacketRetryTimerDpc(   IN PKDPC Dpc,
                                    IN PVOID DeferredContext,
                                    IN PVOID SystemArgument1,
                                    IN PVOID SystemArgument2)
{
    PTRANSFER_PACKET pkt;
    PDEVICE_OBJECT fdo;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;

    _Analysis_assume_(DeferredContext != NULL);
   
    pkt = (PTRANSFER_PACKET)DeferredContext;

    fdo = pkt->Fdo;
    fdoExtension = fdo->DeviceExtension;

    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(SystemArgument1);
    UNREFERENCED_PARAMETER(SystemArgument2);


    /*
     *  Sometimes the port driver can allocates a new 'sense' buffer
     *  to report transfer errors, e.g. when the default sense buffer
     *  is too small.  If so, it is up to us to free it.
     *  Now that we're done using the sense info, free it if appropriate.
     *  Then clear the sense buffer so it doesn't pollute future errors returned in this packet.
     */
    if (PORT_ALLOCATED_SENSE_EX(fdoExtension, pkt->Srb)) {
        TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Freeing port-allocated sense buffer for pkt %ph.", pkt));
        FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, pkt->Srb);
        SrbSetSenseInfoBuffer(pkt->Srb, &pkt->SrbErrorSenseData);
        SrbSetSenseInfoBufferLength(pkt->Srb, sizeof(pkt->SrbErrorSenseData));
    }
    else {
        NT_ASSERT(SrbGetSenseInfoBuffer(pkt->Srb) == &pkt->SrbErrorSenseData);
        NT_ASSERT(SrbGetSenseInfoBufferLength(pkt->Srb) <= sizeof(pkt->SrbErrorSenseData));
    }

    RtlZeroMemory(&pkt->SrbErrorSenseData, sizeof(pkt->SrbErrorSenseData));

    SubmitTransferPacket(pkt);

}
_Use_decl_annotations_
VOID
TXSendCompleteWorkItem(
    PVOID       FunctionContext,
    NDIS_HANDLE WorkItem)
/*++

Routine Description:

    This work item handler is used to do send completions in the case when we are trying
    to avoid a DPC watchdog timeout

Arguments:

    FunctionContext - The Adapter object for which send-completions are to be done

--*/
{
    PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(FunctionContext);
    KIRQL OldIrql;

    UNREFERENCED_PARAMETER(WorkItem);

	ASSERT(Adapter != NULL);
	_Analysis_assume_(Adapter != NULL);
    DEBUGP(MP_TRACE, "[%p] ---> TXSendCompleteWorkItem.\n", Adapter);

    Adapter->SendCompleteWorkItemRunning = TRUE;
    KeMemoryBarrier();

    Adapter->SendCompleteWorkItemQueued = FALSE;
    KeMemoryBarrier();

    NDIS_RAISE_IRQL_TO_DISPATCH(&OldIrql);
    TXSendComplete(Adapter);
    NDIS_LOWER_IRQL(OldIrql,DISPATCH_LEVEL);

    KeMemoryBarrier();
    Adapter->SendCompleteWorkItemRunning = FALSE;

    DEBUGP(MP_TRACE, "[%p] <--- TXSendCompleteWorkItem.\n", Adapter);
}
Exemple #12
0
VOID TransferPacketRetryTimerDpc(   IN PKDPC Dpc,
                                    IN PVOID DeferredContext,
                                    IN PVOID SystemArgument1,
                                    IN PVOID SystemArgument2)
{
    PTRANSFER_PACKET pkt;

    _Analysis_assume_(DeferredContext != NULL);
   
    pkt = (PTRANSFER_PACKET)DeferredContext;


    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(SystemArgument1);
    UNREFERENCED_PARAMETER(SystemArgument2);


    SubmitTransferPacket(pkt);

}
Exemple #13
0
// Returns false if this shader has interface dependencies which are nullptr (SetShader will fail).
bool CEffect::ValidateShaderBlock( _Inout_ SShaderBlock* pBlock )
{
    if( !pBlock->IsValid )
        return false;
    if( pBlock->InterfaceDepCount > 0 )
    {
        assert( pBlock->InterfaceDepCount == 1 );
        for( size_t  i=0; i < pBlock->pInterfaceDeps[0].Count; i++ )
        {
            SInterface* pInterfaceDep = pBlock->pInterfaceDeps[0].ppFXPointers[i];
            assert( pInterfaceDep != 0 );
            _Analysis_assume_( pInterfaceDep != 0 );
            if( pInterfaceDep->pClassInstance == nullptr )
            {
                return false;
            }
        }
    }
    return true;
}
Exemple #14
0
NTSTATUS
PLxInitializeDMA(
    IN PDEVICE_EXTENSION DevExt
    )
/*++
Routine Description:

    Initializes the DMA adapter.

Arguments:

    DevExt      Pointer to our DEVICE_EXTENSION

Return Value:

     None

--*/
{
    NTSTATUS    status;
    WDF_OBJECT_ATTRIBUTES attributes;

    PAGED_CODE();

    //
    // PLx PCI9656 DMA_TRANSFER_ELEMENTS must be 16-byte aligned
    //
    WdfDeviceSetAlignmentRequirement( DevExt->Device,
                                      PCI9656_DTE_ALIGNMENT_16 );

    //
    // Create a new DMA Enabler instance.
    // Use Scatter/Gather, 64-bit Addresses, Duplex-type profile.
    //
    {
        WDF_DMA_ENABLER_CONFIG   dmaConfig;

        WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
                                     WdfDmaProfileScatterGather64Duplex,
                                     DevExt->MaximumTransferLength );

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                    " - The DMA Profile is WdfDmaProfileScatterGather64Duplex");

        status = WdfDmaEnablerCreate( DevExt->Device,
                                      &dmaConfig,
                                      WDF_NO_OBJECT_ATTRIBUTES,
                                      &DevExt->DmaEnabler );

        if (!NT_SUCCESS (status)) {

            TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                        "WdfDmaEnablerCreate failed: %!STATUS!", status);
            return status;
        }
    }

    //
    // Allocate common buffer for building writes
    //
    // NOTE: This common buffer will not be cached.
    //       Perhaps in some future revision, cached option could
    //       be used. This would have faster access, but requires
    //       flushing before starting the DMA in PLxStartWriteDma.
    //
    DevExt->WriteCommonBufferSize =
        sizeof(DMA_TRANSFER_ELEMENT) * DevExt->WriteTransferElements;

    _Analysis_assume_(DevExt->WriteCommonBufferSize > 0);
    status = WdfCommonBufferCreate( DevExt->DmaEnabler,
                                    DevExt->WriteCommonBufferSize,
                                    WDF_NO_OBJECT_ATTRIBUTES,
                                    &DevExt->WriteCommonBuffer );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "WdfCommonBufferCreate (write) failed: %!STATUS!", status);
        return status;
    }


    DevExt->WriteCommonBufferBase =
        WdfCommonBufferGetAlignedVirtualAddress(DevExt->WriteCommonBuffer);

    DevExt->WriteCommonBufferBaseLA =
        WdfCommonBufferGetAlignedLogicalAddress(DevExt->WriteCommonBuffer);

    RtlZeroMemory( DevExt->WriteCommonBufferBase,
                   DevExt->WriteCommonBufferSize);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "WriteCommonBuffer 0x%p  (#0x%I64X), length %I64d",
                DevExt->WriteCommonBufferBase,
                DevExt->WriteCommonBufferBaseLA.QuadPart,
                WdfCommonBufferGetLength(DevExt->WriteCommonBuffer) );

    //
    // Allocate common buffer for building reads
    //
    // NOTE: This common buffer will not be cached.
    //       Perhaps in some future revision, cached option could
    //       be used. This would have faster access, but requires
    //       flushing before starting the DMA in PLxStartReadDma.
    //
    DevExt->ReadCommonBufferSize =
        sizeof(DMA_TRANSFER_ELEMENT) * DevExt->ReadTransferElements;

    _Analysis_assume_(DevExt->ReadCommonBufferSize > 0);
    status = WdfCommonBufferCreate( DevExt->DmaEnabler,
                                    DevExt->ReadCommonBufferSize,
                                    WDF_NO_OBJECT_ATTRIBUTES,
                                    &DevExt->ReadCommonBuffer );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "WdfCommonBufferCreate (read) failed %!STATUS!", status);
        return status;
    }

    DevExt->ReadCommonBufferBase =
        WdfCommonBufferGetAlignedVirtualAddress(DevExt->ReadCommonBuffer);

    DevExt->ReadCommonBufferBaseLA =
        WdfCommonBufferGetAlignedLogicalAddress(DevExt->ReadCommonBuffer);

    RtlZeroMemory( DevExt->ReadCommonBufferBase,
                   DevExt->ReadCommonBufferSize);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "ReadCommonBuffer  0x%p  (#0x%I64X), length %I64d",
                DevExt->ReadCommonBufferBase,
                DevExt->ReadCommonBufferBaseLA.QuadPart,
                WdfCommonBufferGetLength(DevExt->ReadCommonBuffer) );

    //
    // Since we are using sequential queue and processing one request
    // at a time, we will create transaction objects upfront and reuse
    // them to do DMA transfer. Transactions objects are parented to
    // DMA enabler object by default. They will be deleted along with
    // along with the DMA enabler object. So need to delete them
    // explicitly.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT);
    
    status = WdfDmaTransactionCreate( DevExt->DmaEnabler,
                                      &attributes,
                                      &DevExt->ReadDmaTransaction);

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
                    "WdfDmaTransactionCreate(read) failed: %!STATUS!", status);
        return status;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT);
    //
    // Create a new DmaTransaction.
    //
    status = WdfDmaTransactionCreate( DevExt->DmaEnabler,
                                      &attributes,
                                      &DevExt->WriteDmaTransaction );

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
                    "WdfDmaTransactionCreate(write) failed: %!STATUS!", status);
        return status;
    }

    return status;
}
Exemple #15
0
void
error(
    _In_ const char* pszFormat,
    ...)
{
    CHAR szBuffer[512];
    SIZE_T cchBuffer;
    DWORD dwLastError;
    va_list argptr;

    /* Get last error */
    dwLastError = GetLastError();

    va_start(argptr, pszFormat);
    cchBuffer = vsprintf_s(szBuffer, sizeof(szBuffer), pszFormat, argptr);
    va_end(argptr);

    /* Strip trailing newlines */
    _Analysis_assume_(cchBuffer < sizeof(szBuffer));
    while ((cchBuffer >= 1) &&
           ((szBuffer[cchBuffer - 1] == '\r') ||
            (szBuffer[cchBuffer - 1] == '\n')))
    {
        szBuffer[cchBuffer - 1] = '\0';
        cchBuffer--;
    }

    /* Check if we have an error */
    if (dwLastError != ERROR_SUCCESS)
    {
        /* Append error code */
        cchBuffer += sprintf_s(szBuffer + cchBuffer,
                               sizeof(szBuffer) - cchBuffer,
                               " [error %lu: ", dwLastError);

        /* Format the last error code */
        cchBuffer += FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
                                    NULL,
                                    dwLastError,
                                    0,
                                    szBuffer + cchBuffer,
                                    (DWORD)(sizeof(szBuffer) - cchBuffer),
                                    NULL);

        /* Strip trailing newlines */
        _Analysis_assume_(cchBuffer < sizeof(szBuffer));
        while ((cchBuffer >= 1) &&
               ((szBuffer[cchBuffer - 1] == '\r') ||
                (szBuffer[cchBuffer - 1] == '\n')))
        {
            szBuffer[cchBuffer - 1] = '\0';
            cchBuffer--;
        }

        fprintf(stderr, "%s]\n", szBuffer);
    }
    else
    {
        fprintf(stderr, "%s\n", szBuffer);
    }
}
void
TLInspectALERecvAcceptClassify(
   _In_ const FWPS_INCOMING_VALUES* inFixedValues,
   _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
   _Inout_opt_ void* layerData,
   _In_ const FWPS_FILTER* filter,
   _In_ UINT64 flowContext,
   _Inout_ FWPS_CLASSIFY_OUT* classifyOut
   )

#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
/* ++

   This is the classifyFn function for the ALE Recv-Accept (v4 and v6) callout.
   For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
   is not set), it is queued to the connection list for inspection by the
   worker thread. For re-auth, it is queued to the packet queue to be process 
   by the worker thread like any other regular packets.

-- */
{
   NTSTATUS status;

   KLOCK_QUEUE_HANDLE connListLockHandle;
   KLOCK_QUEUE_HANDLE packetQueueLockHandle;

   TL_INSPECT_PENDED_PACKET* pendedRecvAccept = NULL;
   TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;

   ADDRESS_FAMILY addressFamily;
   FWPS_PACKET_INJECTION_STATE packetState;
   BOOLEAN signalWorkerThread;

#if(NTDDI_VERSION >= NTDDI_WIN7)
   UNREFERENCED_PARAMETER(classifyContext);
#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
   UNREFERENCED_PARAMETER(filter);
   UNREFERENCED_PARAMETER(flowContext);

   //
   // We don't have the necessary right to alter the classify, exit.
   //
   if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
   {
      goto Exit;
   }

  NT_ASSERT(layerData != NULL);
  _Analysis_assume_(layerData != NULL);

   //
   // We don't re-inspect packets that we've inspected earlier.
   //
   packetState = FwpsQueryPacketInjectionState(
                     gInjectionHandle,
                     layerData,
                     NULL
                     );

   if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
       (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
   {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
      {
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      }

      goto Exit;
   }

   addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

   if (!IsAleReauthorize(inFixedValues))
   {
      //
      // If the classify is the initial authorization for a connection, we 
      // queue it to the pended connection list and notify the worker thread
      // for out-of-band processing.
      //
      pendedRecvAccept = AllocateAndInitializePendedPacket(
                              inFixedValues,
                              inMetaValues,
                              addressFamily,
                              layerData,
                              TL_INSPECT_CONNECT_PACKET,
                              FWP_DIRECTION_INBOUND
                              );

      if (pendedRecvAccept == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

      //
      // Pend the ALE_AUTH_RECV_ACCEPT classify.
      //
      status = FwpsPendOperation(
                  inMetaValues->completionHandle,
                  &pendedRecvAccept->completionContext
                  );

      if (!NT_SUCCESS(status))
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      signalWorkerThread = IsListEmpty(&gConnList) && 
                           IsListEmpty(&gPacketQueue);

      InsertTailList(&gConnList, &pendedRecvAccept->listEntry);
      pendedRecvAccept = NULL; // ownership transferred

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }

   }
   else // re-auth @ ALE_AUTH_RECV_ACCEPT
   {
      FWP_DIRECTION packetDirection;
      //
      // The classify is the re-authorization for a existing connection, it 
      // could have been triggered for one of the two cases --
      //
      //    1) The re-auth is triggered by an outbound packet sent immediately
      //       after a policy change at ALE_AUTH_RECV_ACCEPT layer.
      //    2) The re-auth is triggered by an inbound packet received 
      //       immediately after a policy change at ALE_AUTH_RECV_ACCEPT layer.
      //

      NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_PACKET_DIRECTION));
      packetDirection = inMetaValues->packetDirection;

      pendedPacket = AllocateAndInitializePendedPacket(
                        inFixedValues,
                        inMetaValues,
                        addressFamily,
                        layerData,
                        TL_INSPECT_REAUTH_PACKET,
                        packetDirection
                        );

      if (pendedPacket == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      if (packetDirection == FWP_DIRECTION_INBOUND)
      {
         pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      if (!gDriverUnloading)
      {
         signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                              IsListEmpty(&gConnList);

         InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
         pendedPacket = NULL; // ownership transferred

         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
      }
      else
      {
         //
         // Driver is being unloaded, permit any connect classify.
         //
         signalWorkerThread = FALSE;

         classifyOut->actionType = FWP_ACTION_PERMIT;
         if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
         {
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         }
      }

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }
   }

Exit:

   if (pendedPacket != NULL)
   {
      FreePendedPacket(pendedPacket);
   }
   if (pendedRecvAccept != NULL)
   {
      FreePendedPacket(pendedRecvAccept);
   }

   return;
}
void
TLInspectTransportClassify(
   _In_ const FWPS_INCOMING_VALUES* inFixedValues,
   _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
   _Inout_opt_ void* layerData,
   _In_ const FWPS_FILTER* filter,
   _In_ UINT64 flowContext,
   _Inout_ FWPS_CLASSIFY_OUT* classifyOut
   )

#endif
/* ++

   This is the classifyFn function for the Transport (v4 and v6) callout.
   packets (inbound or outbound) are ueued to the packet queue to be processed 
   by the worker thread.

-- */
{

   KLOCK_QUEUE_HANDLE connListLockHandle;
   KLOCK_QUEUE_HANDLE packetQueueLockHandle;

   TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
   FWP_DIRECTION packetDirection;

   ADDRESS_FAMILY addressFamily;
   FWPS_PACKET_INJECTION_STATE packetState;
   BOOLEAN signalWorkerThread;

#if(NTDDI_VERSION >= NTDDI_WIN7)
   UNREFERENCED_PARAMETER(classifyContext);
#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
   UNREFERENCED_PARAMETER(filter);
   UNREFERENCED_PARAMETER(flowContext);

   //
   // We don't have the necessary right to alter the classify, exit.
   //
   if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
   {
      goto Exit;
   }

  NT_ASSERT(layerData != NULL);
  _Analysis_assume_(layerData != NULL);

   //
   // We don't re-inspect packets that we've inspected earlier.
   //
   packetState = FwpsQueryPacketInjectionState(
                     gInjectionHandle,
                     layerData,
                     NULL
                     );

   if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
       (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
   {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
      {
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      }

      goto Exit;
   }

   addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

   packetDirection = 
      GetPacketDirectionForLayer(inFixedValues->layerId);

   if (packetDirection == FWP_DIRECTION_INBOUND)
   {
      if (IsAleClassifyRequired(inFixedValues, inMetaValues))
      {
         //
         // Inbound transport packets that are destined to ALE Recv-Accept 
         // layers, for initial authorization or reauth, should be inspected 
         // at the ALE layer. We permit it from Tranport here.
         //
         classifyOut->actionType = FWP_ACTION_PERMIT;
         if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
         {
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         }
         goto Exit;
      }
      else
      {
         //
         // To be compatible with Vista's IpSec implementation, we must not
         // intercept not-yet-detunneled IpSec traffic.
         //
         FWPS_PACKET_LIST_INFORMATION packetInfo = {0};
         FwpsGetPacketListSecurityInformation(
            layerData,
            FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC |
            FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND,
            &packetInfo
            );

         if (packetInfo.ipsecInformation.inbound.isTunnelMode &&
             !packetInfo.ipsecInformation.inbound.isDeTunneled)
         {
            classifyOut->actionType = FWP_ACTION_PERMIT;
            if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
            {
               classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            }
            goto Exit;
         }
      }
   }

   pendedPacket = AllocateAndInitializePendedPacket(
                     inFixedValues,
                     inMetaValues,
                     addressFamily,
                     layerData,
                     TL_INSPECT_DATA_PACKET,
                     packetDirection
                     );

   if (pendedPacket == NULL)
   {
      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      goto Exit;
   }

   KeAcquireInStackQueuedSpinLock(
      &gConnListLock,
      &connListLockHandle
      );
   KeAcquireInStackQueuedSpinLock(
      &gPacketQueueLock,
      &packetQueueLockHandle
      );

   if (!gDriverUnloading)
   {
      signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                           IsListEmpty(&gConnList);

      InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
      pendedPacket = NULL; // ownership transferred

      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
   }
   else
   {
      //
      // Driver is being unloaded, permit any connect classify.
      //
      signalWorkerThread = FALSE;

      classifyOut->actionType = FWP_ACTION_PERMIT;
      if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
      {
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      }
   }

   KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
   KeReleaseInStackQueuedSpinLock(&connListLockHandle);

   if (signalWorkerThread)
   {
      KeSetEvent(
         &gWorkerEvent, 
         0, 
         FALSE
         );
   }

Exit:

   if (pendedPacket != NULL)
   {
      FreePendedPacket(pendedPacket);
   }

   return;
}
VOID
EvtIoDeviceControl(
    _In_  WDFQUEUE          Queue,
    _In_  WDFREQUEST        Request,
    _In_  size_t            OutputBufferLength,
    _In_  size_t            InputBufferLength,
    _In_  ULONG             IoControlCode
    )
/*++
Routine Description:

    This event callback function is called when the driver receives an

    (KMDF) IOCTL_HID_Xxx code when handlng IRP_MJ_INTERNAL_DEVICE_CONTROL
    (UMDF) IOCTL_HID_Xxx, IOCTL_UMDF_HID_Xxx when handling IRP_MJ_DEVICE_CONTROL

Arguments:

    Queue - A handle to the queue object that is associated with the I/O request

    Request - A handle to a framework request object.

    OutputBufferLength - The length, in bytes, of the request's output buffer,
            if an output buffer is available.

    InputBufferLength - The length, in bytes, of the request's input buffer, if
            an input buffer is available.

    IoControlCode - The driver or system defined IOCTL associated with the request

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS                status;
    BOOLEAN                 completeRequest = TRUE;
    WDFDEVICE               device = WdfIoQueueGetDevice(Queue);
    PDEVICE_CONTEXT         deviceContext = NULL;
    PQUEUE_CONTEXT          queueContext = GetQueueContext(Queue);
    UNREFERENCED_PARAMETER  (OutputBufferLength);
    UNREFERENCED_PARAMETER  (InputBufferLength);

    deviceContext = GetDeviceContext(device);

    switch (IoControlCode)
    {
    case IOCTL_HID_GET_DEVICE_DESCRIPTOR:   // METHOD_NEITHER
        //
        // Retrieves the device's HID descriptor.
        //
        _Analysis_assume_(deviceContext->HidDescriptor.bLength != 0);
        status = RequestCopyFromBuffer(Request,
                            &deviceContext->HidDescriptor,
                            deviceContext->HidDescriptor.bLength);
        break;

    case IOCTL_HID_GET_DEVICE_ATTRIBUTES:   // METHOD_NEITHER
        //
        //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure.
        //
        status = RequestCopyFromBuffer(Request,
                            &queueContext->DeviceContext->HidDeviceAttributes,
                            sizeof(HID_DEVICE_ATTRIBUTES));
        break;

    case IOCTL_HID_GET_REPORT_DESCRIPTOR:   // METHOD_NEITHER
        //
        //Obtains the report descriptor for the HID device.
        //
        status = RequestCopyFromBuffer(Request,
                            deviceContext->ReportDescriptor,
                            deviceContext->HidDescriptor.DescriptorList[0].wReportLength);
        break;

    case IOCTL_HID_READ_REPORT:             // METHOD_NEITHER
        //
        // Returns a report from the device into a class driver-supplied
        // buffer.
        //
        status = ReadReport(queueContext, Request, &completeRequest);
        break;

    case IOCTL_HID_WRITE_REPORT:            // METHOD_NEITHER
        //
        // Transmits a class driver-supplied report to the device.
        //
        status = WriteReport(queueContext, Request);
        break;

#ifdef _KERNEL_MODE

    case IOCTL_HID_GET_FEATURE:             // METHOD_OUT_DIRECT

        status = GetFeature(queueContext, Request);
        break;

    case IOCTL_HID_SET_FEATURE:             // METHOD_IN_DIRECT

        status = SetFeature(queueContext, Request);
        break;

    case IOCTL_HID_GET_INPUT_REPORT:        // METHOD_OUT_DIRECT

        status = GetInputReport(queueContext, Request);
        break;

    case IOCTL_HID_SET_OUTPUT_REPORT:       // METHOD_IN_DIRECT

        status = SetOutputReport(queueContext, Request);
        break;

#else // UMDF specific

    //
    // HID minidriver IOCTL uses HID_XFER_PACKET which contains an embedded pointer.
    //
    //   typedef struct _HID_XFER_PACKET {
    //     PUCHAR reportBuffer;
    //     ULONG  reportBufferLen;
    //     UCHAR  reportId;
    //   } HID_XFER_PACKET, *PHID_XFER_PACKET;
    //
    // UMDF cannot handle embedded pointers when marshalling buffers between processes.
    // Therefore a special driver mshidumdf.sys is introduced to convert such IRPs to
    // new IRPs (with new IOCTL name like IOCTL_UMDF_HID_Xxxx) where:
    //
    //   reportBuffer - passed as one buffer inside the IRP
    //   reportId     - passed as a second buffer inside the IRP
    //
    // The new IRP is then passed to UMDF host and driver for further processing.
    //

    case IOCTL_UMDF_HID_GET_FEATURE:        // METHOD_NEITHER

        status = GetFeature(queueContext, Request);
        break;

    case IOCTL_UMDF_HID_SET_FEATURE:        // METHOD_NEITHER

        status = SetFeature(queueContext, Request);
        break;

    case IOCTL_UMDF_HID_GET_INPUT_REPORT:  // METHOD_NEITHER

        status = GetInputReport(queueContext, Request);
        break;

    case IOCTL_UMDF_HID_SET_OUTPUT_REPORT: // METHOD_NEITHER

        status = SetOutputReport(queueContext, Request);
        break;

#endif // _KERNEL_MODE

    case IOCTL_HID_GET_STRING:                      // METHOD_NEITHER

        status = GetString(Request);
        break;

    case IOCTL_HID_GET_INDEXED_STRING:              // METHOD_OUT_DIRECT

        status = GetIndexedString(Request);
        break;

    case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:  // METHOD_NEITHER
        //
        // This has the USBSS Idle notification callback. If the lower driver
        // can handle it (e.g. USB stack can handle it) then pass it down
        // otherwise complete it here as not inplemented. For a virtual
        // device, idling is not needed.
        //
        // Not implemented. fall through...
        //
    case IOCTL_HID_ACTIVATE_DEVICE:                 // METHOD_NEITHER
    case IOCTL_HID_DEACTIVATE_DEVICE:               // METHOD_NEITHER
    case IOCTL_GET_PHYSICAL_DESCRIPTOR:             // METHOD_OUT_DIRECT
        //
        // We don't do anything for these IOCTLs but some minidrivers might.
        //
        // Not implemented. fall through...
        //
    default:
        status = STATUS_NOT_IMPLEMENTED;
        break;
    }

    //
    // Complete the request. Information value has already been set by request
    // handlers.
    //
    if (completeRequest) {
        WdfRequestComplete(Request, status);
    }
}
void
TLInspectWorker(
   _In_ void* StartContext
   )
/* ++

   This worker thread waits for the connect and packet queue event when the 
   queues are empty; and it will be woken up when there are connects/packets 
   queued needing to be inspected. Once awaking, It will run in a loop to 
   complete the pended ALE classifies and/or clone-reinject packets back 
   until both queues are exhausted (and it will go to sleep waiting for more 
   work).

   The worker thread will end once it detected the driver is unloading.

-- */
{
   NTSTATUS status;

   TL_INSPECT_PENDED_PACKET* packet = NULL;
   LIST_ENTRY* listEntry;

   KLOCK_QUEUE_HANDLE packetQueueLockHandle;
   KLOCK_QUEUE_HANDLE connListLockHandle;

   UNREFERENCED_PARAMETER(StartContext);

   for(;;)
   {
      KeWaitForSingleObject(
         &gWorkerEvent,
         Executive, 
         KernelMode, 
         FALSE, 
         NULL
         );

      if (gDriverUnloading)
      {
         break;
      }

      configPermitTraffic = IsTrafficPermitted();

      listEntry = NULL;

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );

      if (!IsListEmpty(&gConnList))
      {
         _Analysis_assume_(gConnList.Flink != NULL);
         listEntry = gConnList.Flink;

         packet = CONTAINING_RECORD(
                           listEntry,
                           TL_INSPECT_PENDED_PACKET,
                           listEntry
                           );
         if (packet->direction == FWP_DIRECTION_INBOUND)
         {
            RemoveEntryList(&packet->listEntry);
         }

         //
         // Leave the pended ALE_AUTH_CONNECT in the connection list, it will
         // be processed and removed from the list during re-auth.
         //
      }

      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      if (listEntry == NULL)
      {
         NT_ASSERT(!IsListEmpty(&gPacketQueue));

         KeAcquireInStackQueuedSpinLock(
            &gPacketQueueLock,
            &packetQueueLockHandle
            );

         listEntry = RemoveHeadList(&gPacketQueue);

         packet = CONTAINING_RECORD(
                           listEntry,
                           TL_INSPECT_PENDED_PACKET,
                           listEntry
                           );

         KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      }

      if (packet->type == TL_INSPECT_CONNECT_PACKET)
      {
         TlInspectCompletePendedConnection(
            &packet,
            configPermitTraffic);
      }

      if ((packet != NULL) && configPermitTraffic)
      {
         if (packet->direction == FWP_DIRECTION_OUTBOUND)
         {
            status = TLInspectCloneReinjectOutbound(packet);
         }
         else
         {
            status = TLInspectCloneReinjectInbound(packet);
         }

         if (NT_SUCCESS(status))
         {
            packet = NULL; // ownership transferred.
         }

      }

      if (packet != NULL)
      {
         FreePendedPacket(packet);
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue) &&
          !gDriverUnloading)
      {
         KeClearEvent(&gWorkerEvent);
      }

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);
   }

   NT_ASSERT(gDriverUnloading);

   while (!IsListEmpty(&gConnList))
   {
      packet = NULL;

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );

      if (!IsListEmpty(&gConnList))
      {
         listEntry = gConnList.Flink;
         packet = CONTAINING_RECORD(
                           listEntry,
                           TL_INSPECT_PENDED_PACKET,
                           listEntry
                           );
      }

      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      if (packet != NULL)
      {
         TlInspectCompletePendedConnection(&packet, FALSE);
         NT_ASSERT(packet == NULL);
      }
   }

   //
   // Discard all the pended packets if driver is being unloaded.
   //

   while (!IsListEmpty(&gPacketQueue))
   {
      packet = NULL;

      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      if (!IsListEmpty(&gPacketQueue))
      {
         listEntry = RemoveHeadList(&gPacketQueue);

         packet = CONTAINING_RECORD(
                           listEntry,
                           TL_INSPECT_PENDED_PACKET,
                           listEntry
                           );
      }

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      
      if (packet != NULL)
      {
         FreePendedPacket(packet);
      }
   }

   PsTerminateSystemThread(STATUS_SUCCESS);

}
Exemple #20
0
VOID
EchoEvtIoRead(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request,
    IN size_t      Length
    )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_READ request.
    It will copy the content from the queue-context buffer to the request buffer.
    If the driver hasn't received any write request earlier, the read returns zero.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length  - number of bytes to be read.
              The default property of the queue is to not dispatch
              zero lenght read & write requests to the driver and
              complete is with status success. So we will never get
              a zero length request.

Return Value:

    VOID

--*/
{
    NTSTATUS Status;
    PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
    WDFMEMORY memory;
    size_t writeMemoryLength;

    _Analysis_assume_(Length > 0);

    KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n",
             Queue,Request,Length));
    //
    // No data to read
    //
    if( (queueContext->WriteMemory == NULL)  ) {
        WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);
        return;
    }

    //
    // Read what we have
    //
    WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength);
    _Analysis_assume_(writeMemoryLength > 0);

    if( writeMemoryLength < Length ) {
        Length = writeMemoryLength;
    }

    //
    // Get the request memory
    //
    Status = WdfRequestRetrieveOutputMemory(Request, &memory);
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status));
        WdfVerifierDbgBreakPoint();
        WdfRequestCompleteWithInformation(Request, Status, 0L);
        return;
    }

    // Copy the memory out
    Status = WdfMemoryCopyFromBuffer( memory, // destination
                             0,      // offset into the destination memory
                             WdfMemoryGetBuffer(queueContext->WriteMemory, NULL),
                             Length );
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status));
        WdfRequestComplete(Request, Status);
        return;
    }

    // Set transfer information
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    // Mark the request is cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);


    // Defer the completion to another thread from the timer dpc
    queueContext->CurrentRequest = Request;
    queueContext->CurrentStatus  = Status;

    return;
}
Exemple #21
0
//
// Routine Description:
//
//  PL011pRxPioBufferCopy is called to copy new RX data from PIO RX buffer 
//  to the caller RX buffer.
//
// Arguments:
//
//  DevExtPtr - Our device context.
//
//  BufferPtr - The caller buffer into which FIFO bytes should be
//      transferred.
//
//  Length - Size in bytes of the caller buffer.
//
// Return Value:
//
//  Number of bytes successfully written to caller buffer.
//
_Use_decl_annotations_
ULONG
PL011pRxPioBufferCopy(
    PL011_DEVICE_EXTENSION* DevExtPtr,
    UCHAR* BufferPtr,
    ULONG Length
    )
{
    PL011_SERCXPIORECEIVE_CONTEXT* rxPioPtr =
        PL011SerCxPioReceiveGetContext(DevExtPtr->SerCx2PioReceive);

    //
    // Get number of bytes we can copy.
    // Is RX buffer empty ?
    //
    ULONG bytesToCopy = min(PL011pRxPendingByteCount(rxPioPtr), Length);
    if (bytesToCopy == 0) {

        return 0;
    }

    //
    // Copy RX data: RX Buffer -> Caller buffer
    //
    ULONG rxOut = rxPioPtr->RxBufferOut;
    ULONG bytesCopied = min(bytesToCopy, (PL011_RX_BUFFER_SIZE_BYTES - rxOut));

    _Analysis_assume_(bytesCopied <= Length);
    RtlCopyMemory(BufferPtr, &rxPioPtr->RxBuffer[rxOut], bytesCopied);

    rxOut = (rxOut + bytesCopied) % PL011_RX_BUFFER_SIZE_BYTES;

    if (bytesCopied < bytesToCopy) {

        BufferPtr += bytesCopied;

        ULONG bytesLeftToCopy = bytesToCopy - bytesCopied;
        RtlCopyMemory(BufferPtr, &rxPioPtr->RxBuffer, bytesLeftToCopy);

        bytesCopied += bytesLeftToCopy;
        rxOut = bytesLeftToCopy;

    } // if (bytesCopied < bytesToCopy)

    rxPioPtr->RxBufferOut = rxOut;
    InterlockedAdd(&rxPioPtr->RxBufferCount, -LONG(bytesCopied));

    if (bytesCopied != 0) {

        PL011_LOG_TRACE(
            "RX buffer: read %lu chars, buffer length %lu, in %lu, out %lu, count %lu",
            bytesCopied,
            Length,
            rxPioPtr->RxBufferIn,
            rxPioPtr->RxBufferOut,
            rxPioPtr->RxBufferCount
            );
    }

    return bytesCopied;
}
NTSTATUS
ToastMon_PnpNotifyInterfaceChange(
    _In_ PVOID NotificationStruct,
    _Inout_opt_ PVOID Context
    )
/*++

Routine Description:

    This routine is the PnP "interface change notification" callback routine.

    This gets called on a Toaster triggered device interface arrival or
    removal.
      - Interface arrival corresponds to a Toaster device being STARTED
      - Interface removal corresponds to a Toaster device being REMOVED

    On arrival:
      - Create a IoTarget and open it by using the symboliclink. WDF will
         Register for EventCategoryTargetDeviceChange notification on the fileobject
        so it can cleanup whenever associated device is removed.

    On removal:
      - This callback is a NO-OP for interface removal because framework registers
      for PnP EventCategoryTargetDeviceChange callbacks and
      uses that callback to clean up when the associated toaster device goes
      away.

Arguments:

    NotificationStruct  - Structure defining the change.

    Context -    pointer to the device extension.
                 (supplied as the "context" when we
                  registered for this callback)
Return Value:

    STATUS_SUCCESS - always, even if something goes wrong

    status is only used during query removal notifications and the OS ignores other
    cases

--*/
{
    NTSTATUS                    status = STATUS_SUCCESS;
    PDEVICE_EXTENSION           deviceExtension = Context;
    WDFIOTARGET                 ioTarget;
    PDEVICE_INTERFACE_CHANGE_NOTIFICATION devNotificationStruct = NotificationStruct;

    _Analysis_assume_(NULL != deviceExtension);

    PAGED_CODE();

    KdPrint(("Entered ToastMon_PnpNotifyInterfaceChange\n"));

    //
    // Verify that interface class is a toaster device interface.
    //
    ASSERT(IsEqualGUID( (LPGUID)&(devNotificationStruct->InterfaceClassGuid),
                      (LPGUID)&GUID_DEVINTERFACE_TOASTER));

    //
    // Check the callback event.
    //
    if(IsEqualGUID( (LPGUID)&(devNotificationStruct->Event),
                     (LPGUID)&GUID_DEVICE_INTERFACE_ARRIVAL )) {

        KdPrint(("Arrival Notification\n"));

        status = Toastmon_OpenDevice((WDFDEVICE)deviceExtension->WdfDevice,
                                                (PUNICODE_STRING)devNotificationStruct->SymbolicLinkName,
                                                &ioTarget);
        if (!NT_SUCCESS(status)) {
            KdPrint( ("Unable to open control device 0x%x\n", status));
            return status;
        }

        //
        // Add this one to the collection.
        //
        WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL);

        //
        // WdfCollectionAdd takes a reference on the request object and removes
        // it when you call WdfCollectionRemove.
        //
        status = WdfCollectionAdd(deviceExtension->TargetDeviceCollection, ioTarget);
        if (!NT_SUCCESS(status)) {
            KdPrint( ("WdfCollectionAdd failed 0x%x\n", status));
            WdfObjectDelete(ioTarget); // Delete will also close the target
        }

        WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock);


    } else {

        KdPrint(("Removal Interface Notification\n"));
    }
    return STATUS_SUCCESS;
}
VOID
ndisprotServiceReads(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext
    )
/*++

Routine Description:

    Utility routine to copy received data into user buffers and
    complete READ IRPs.

Arguments:

    pOpenContext - pointer to open context

Return Value:

    None

--*/
{
    PIRP                pIrp = NULL;
    PLIST_ENTRY         pIrpEntry;
    PNET_BUFFER_LIST    pRcvNetBufList;
    PLIST_ENTRY         pRcvNetBufListEntry;
    PUCHAR              pSrc, pDst;
    ULONG               BytesRemaining; // at pDst
    PMDL                pMdl;
    ULONG               BytesAvailable;
    BOOLEAN             FoundPendingIrp = FALSE;
    ULONG               SrcTotalLength = 0; // Source NetBuffer DataLenght
    ULONG               Offset = 0;         // CurrentMdlOffset
    ULONG               BytesToCopy = 0;

    DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
            pOpenContext, pOpenContext->Flags));

    NPROT_REF_OPEN(pOpenContext);  // temp ref - service reads

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
           !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
    {
        FoundPendingIrp = FALSE;

        //
        //  Get the first pended Read IRP
        //
        pIrpEntry = pOpenContext->PendedReads.Flink;
        while (pIrpEntry != &pOpenContext->PendedReads)
        {
            pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);

            //
            //  Check to see if it is being cancelled.
            //
            if (IoSetCancelRoutine(pIrp, NULL))
            {
                //
                //  It isn't being cancelled, and can't be cancelled henceforth.
                //
                NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
                FoundPendingIrp = TRUE;
                break;

                //
                //  NOTE: we decrement PendedReadCount way below in the
                //  while loop, to avoid letting through a thread trying
                //  to unbind.
                //
            }
            else
            {
                //
                //  The IRP is being cancelled; let the cancel routine handle it.
                //
                DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
                        pOpenContext, pIrp));

                pIrpEntry = pIrpEntry->Flink;
            }
        }

        if (FoundPendingIrp == FALSE)
        {
            break;
        }
        //
        //  Get the first queued receive packet
        //
        pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
        NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);

        pOpenContext->RecvNetBufListCount --;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        NPROT_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet

        pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
        NPROT_ASSERT(pRcvNetBufList != NULL);
        _Analysis_assume_(pRcvNetBufList != NULL);
        NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;

        //
        //  Copy as much data as possible from the receive packet to
        //  the IRP MDL.
        //
        
        pDst = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority);
        NPROT_ASSERT(pDst != NULL);  // since it was already mapped
        _Analysis_assume_(pDst != NULL);

        pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        //
        // Copy the data in the received packet into the buffer provided by the client.
        // If the length of the receive packet is greater than length of the given buffer,
        // we just copy as many bytes as we can. Once the buffer is full, we just discard
        // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
        //

        SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
        Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        while (BytesRemaining && (pMdl != NULL) && SrcTotalLength)
        {
            pSrc = NULL;
            NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority);

            if (pSrc == NULL)
            {
                DEBUGP(DL_FATAL,
                    ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n",
                            pOpenContext, pMdl));
                break;
            }

            NPROT_ASSERT(BytesAvailable > Offset);

            BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining);
            BytesToCopy = MIN(BytesToCopy, SrcTotalLength);

            NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy);
            BytesRemaining -= BytesToCopy;
            pDst += BytesToCopy;
            SrcTotalLength -= BytesToCopy;

            //
            // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0.
            //
            Offset = 0;

            NdisGetNextMdl(pMdl, &pMdl);
        }

        //
        //  Complete the IRP.
        //
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;

        DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
            pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE);


        NPROT_DEREF_OPEN(pOpenContext);    // took out pended Read

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
        pOpenContext->PendedReadCount--;

    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    NPROT_DEREF_OPEN(pOpenContext);    // temp ref - service reads
}
VOID
Toastmon_ReadRequestCompletionRoutine(
    IN WDFREQUEST                  Request,
    IN WDFIOTARGET                 Target,
    PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
    IN WDFCONTEXT                  Context
    )
/*++

Routine Description:

    Completion Routine

Arguments:

    CompletionParams - Contains the results of the transfer such as
                                    IoStatus, Length, Buffer, etc.

    Context - context value specified in the WdfRequestSetCompletionRoutine

Return Value:

    VOID

--*/
{
    WDF_REQUEST_REUSE_PARAMS    params;
    PTARGET_DEVICE_INFO       targetInfo;
    NTSTATUS status;

    UNREFERENCED_PARAMETER(Context);

    targetInfo = GetTargetDeviceInfo(Target);
    
    //
    // Delete the memory object because we create a new one every time we post
    // the request. For perf reason, it would be better to preallocate the memory
    // object once.
    // Also for driver created requests, do not call WdfRequestRetrieve functions to get
    // the buffers. They can be called only for requests delivered by the queue.
    //
    WdfObjectDelete(CompletionParams->Parameters.Read.Buffer);

    //
    // Scrub the request for reuse.
    //
    WDF_REQUEST_REUSE_PARAMS_INIT(&params, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_SUCCESS);

    status = WdfRequestReuse(Request, &params);
    ASSERT(NT_SUCCESS(status));
    _Analysis_assume_(NT_SUCCESS(status));
    //
    // RequestReuse zero all the values in structure pointed by CompletionParams.
    // So you must get all the information from completion params before
    // calling RequestReuse.
    //

    targetInfo->ReadRequest = Request;

    //
    // Don't repost the request in the completion routine because it may lead to recursion
    // if the driver below completes the request synchronously.
    //
    return;
}
void
StreamOobEditWorker(
   _In_ void* StartContext
   )
/* ++

   This function waits for an event which gets signalled when there is data
   waiting to be inspected.

   Once awaken, the worker thread edits the stream until all stream data is
   processed (and then it waits for more work again).

   When requested to shutdown, it will finish the editing task and enters
   "shutdown" state.

-- */
{
   NTSTATUS status = STATUS_SUCCESS;

   NET_BUFFER_LIST* netBufferListChain = NULL;
   size_t totalDataLength;
   STREAM_EDITOR* streamEditor = (STREAM_EDITOR*)StartContext;
   DWORD streamFlags;

   for(;;)
   {
      KLOCK_QUEUE_HANDLE editLockHandle;

      KeWaitForSingleObject(
         &streamEditor->oobEditInfo.editEvent,
         Executive, 
         KernelMode, 
         FALSE, 
         NULL
         );

      if (streamEditor->oobEditInfo.editState == OOB_EDIT_ERROR ||
          streamEditor->oobEditInfo.editState == OOB_EDIT_SHUT_DOWN)
      {
         break;
      }

      KeAcquireInStackQueuedSpinLock(
         &streamEditor->oobEditInfo.editLock,
         &editLockHandle
         );

      NT_ASSERT(streamEditor->oobEditInfo.editState == OOB_EDIT_PROCESSING ||
             streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY);

      netBufferListChain = streamEditor->oobEditInfo.nblHead;
      totalDataLength = streamEditor->oobEditInfo.totalDataLength;
      streamFlags = streamEditor->oobEditInfo.streamFlags;

      streamEditor->oobEditInfo.nblHead = NULL;
      streamEditor->oobEditInfo.nblTail = NULL;
      streamEditor->oobEditInfo.totalDataLength = 0;

      KeReleaseInStackQueuedSpinLock(&editLockHandle);

      _Analysis_assume_(netBufferListChain != NULL);
      status = StreamOobEditData(
                  streamEditor,
                  netBufferListChain,
                  totalDataLength,
                  streamFlags
                  );

      if (!NT_SUCCESS(status))
      {
         streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
         break;
      }

      if (streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY)
      {
         NTSTATUS streamContinueStatus;
         streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;
         
         streamContinueStatus = FwpsStreamContinue(
                                   streamEditor->oobEditInfo.flowId, 
                                   streamEditor->oobEditInfo.calloutId,
                                   streamEditor->oobEditInfo.layerId,
                                   streamEditor->oobEditInfo.streamFlags
                                   );

         if (!NT_SUCCESS(streamContinueStatus))
         {
            streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
            break;
         }
      }

      KeAcquireInStackQueuedSpinLock(
         &streamEditor->oobEditInfo.editLock,
         &editLockHandle
         );

      if (streamEditor->oobEditInfo.nblHead == NULL)
      {
         if (!streamEditor->oobEditInfo.shuttingDown)
         {
            streamEditor->oobEditInfo.editState = OOB_EDIT_IDLE;
            KeClearEvent(&streamEditor->oobEditInfo.editEvent);
         }
         else
         {
            streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;
         }
      }

      KeReleaseInStackQueuedSpinLock(&editLockHandle);
   }

   PsTerminateSystemThread(status);
}
/*++

Routine Name:

    CPTManager::GetCapabilities

Routine Description:

    This routine retrieves a PrintCapabilities document given a PrintTicket

Arguments:

    pTicket - Pointer to the PrintTicket as a DOM document
    pTicket - Pointer to a DOM document pointer that recieves the PrintCapabilities

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPTManager::GetCapabilities(
    _In_        IXMLDOMDocument2*  pTicket,
    _Outptr_ IXMLDOMDocument2** ppCapabilities
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pTicket, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(ppCapabilities, E_POINTER)))
    {
        *ppCapabilities = NULL;

        CComBSTR bstrError;
        CComPtr<IStream> pPTIn(NULL);
        CComPtr<IStream> pPCOut(NULL);
        CComPtr<IXMLDOMDocument2> pCapabilitiesDoc(NULL);

        //
        // Create the PrintCapabilities DOM document, retrieve the IStreams from the
        // DOM documents and call the PT api to retrieve the capabilities document
        //
        if (SUCCEEDED(hr = pCapabilitiesDoc.CoCreateInstance(CLSID_DOMDocument60)) &&
            SUCCEEDED(hr = pTicket->QueryInterface(IID_IStream, reinterpret_cast<VOID**>(&pPTIn))) &&
            SUCCEEDED(hr = pCapabilitiesDoc->QueryInterface(IID_IStream, reinterpret_cast<VOID**>(&pPCOut))))
        {
            if (SetThreadToken(NULL, m_hToken))
            {
                if (SUCCEEDED(hr = PTGetPrintCapabilities(m_hProvider, pPTIn, pPCOut, &bstrError)))
                {
                    LARGE_INTEGER cbMove = {0};
                    if (SUCCEEDED(hr = pPCOut->Seek(cbMove, STREAM_SEEK_SET, NULL)))
                    {
                        *ppCapabilities = pCapabilitiesDoc.Detach();
                    }
                }
                else
                {
                    try
                    {
                        CStringXDA cstrError(bstrError);
                        ERR(cstrError.GetBuffer());
                    }
                    catch (CXDException&)
                    {
                    }
                }
            
                //
                // Always revert back to the default security context
                //
                if (!SetThreadToken(NULL, NULL))
                {
                    //
                    // We couldn't revert the security context. The filter pipeline
                    // manager will clean up the thread when operation is complete,
                    // when it is determined that the security context was not 
                    // reverted. Since there are no security implications with 
                    // running this filter in an elevated context, we can 
                    // continue to run.
                    //
                }
            }
            else
            {
                hr = HRESULT_FROM_WIN32(GetLastError());

                //
                // If SetThreadToken fails, GetLastError will return an error
                //
                _Analysis_assume_(FAILED(hr));
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}
//--------------------------------------------------------------------------------------
// Encode the source texture to BC7 and store the result in a buffer
// The source texture can only have 1 sub resource, i.e. it must be a signle 2D texture which has only 1 mip level
// The job of breaking down texture arrays, or texture with multiple mip levels is taken care of in the base class
//--------------------------------------------------------------------------------------
HRESULT CGPUBC7Encoder::GPU_Encode( ID3D11Device* pDevice, ID3D11DeviceContext* pContext,
                                    ID3D11Texture2D* pSrcTexture, 
                                    DXGI_FORMAT dstFormat, ID3D11Buffer** ppDstTextureAsBufOut )
{
    ID3D11ShaderResourceView* pSRV = nullptr;
    ID3D11Buffer* pErrBestModeBuffer[2] = { nullptr, nullptr };
    ID3D11UnorderedAccessView* pUAV = nullptr;
    ID3D11UnorderedAccessView* pErrBestModeUAV[2] = { nullptr, nullptr };
    ID3D11ShaderResourceView* pErrBestModeSRV[2] = { nullptr, nullptr };
    ID3D11Buffer* pCBCS = nullptr;

    if ( !(dstFormat == DXGI_FORMAT_BC7_UNORM || dstFormat == DXGI_FORMAT_BC7_UNORM_SRGB) || 
         !ppDstTextureAsBufOut )
    {
        return E_INVALIDARG;
    }

    D3D11_TEXTURE2D_DESC texSrcDesc;
    pSrcTexture->GetDesc( &texSrcDesc );

    HRESULT hr = S_OK;

    // Create a SRV for input texture        
    {
        D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
        SRVDesc.Texture2D.MipLevels = texSrcDesc.MipLevels;
        SRVDesc.Texture2D.MostDetailedMip = 0;
        SRVDesc.Format = texSrcDesc.Format;
        SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        V_GOTO( pDevice->CreateShaderResourceView( pSrcTexture, &SRVDesc, &pSRV ) );

#if defined(_DEBUG) || defined(PROFILE)
        if ( pSRV )
        {
            pSRV->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 SRV" ) - 1, "BC7 SRV" );
        }
#endif
    }

    // Create output buffer    
    D3D11_BUFFER_DESC sbOutDesc;
    {
        sbOutDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
        sbOutDesc.CPUAccessFlags = 0;
        sbOutDesc.Usage = D3D11_USAGE_DEFAULT;
        sbOutDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
        sbOutDesc.StructureByteStride = sizeof( BufferBC6HBC7 );
        sbOutDesc.ByteWidth = texSrcDesc.Height * texSrcDesc.Width * sizeof( BufferBC6HBC7 ) / BLOCK_SIZE;
        //+ texSrcDesc.Height * texSrcDesc.Width * sizeof( BufferBC7 ) * 5;//For dump
        V_GOTO( pDevice->CreateBuffer(&sbOutDesc, nullptr, ppDstTextureAsBufOut) );
        V_GOTO( pDevice->CreateBuffer(&sbOutDesc, nullptr, &pErrBestModeBuffer[0]) );
        V_GOTO( pDevice->CreateBuffer(&sbOutDesc, nullptr, &pErrBestModeBuffer[1]) );

        _Analysis_assume_( pErrBestModeBuffer[0] != 0 );

#if defined(_DEBUG) || defined(PROFILE)
        if ( *ppDstTextureAsBufOut )
        {
            (*ppDstTextureAsBufOut)->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 Dest" ) - 1, "BC7 Dest" );
        }
        if ( pErrBestModeBuffer[0] )
        {
            pErrBestModeBuffer[0]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest0" ) - 1, "BC7 ErrBest0" );
        }
        if ( pErrBestModeBuffer[1] )
        {
            pErrBestModeBuffer[1]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest1" ) - 1, "BC7 ErrBest1" );
        }
#endif
    }

    // Create UAV of the output texture    
    {
        D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {};
        UAVDesc.Buffer.FirstElement = 0;
        UAVDesc.Buffer.NumElements = sbOutDesc.ByteWidth / sbOutDesc.StructureByteStride;
        UAVDesc.Format = DXGI_FORMAT_UNKNOWN;
        UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
#pragma warning (push)
#pragma warning (disable:6387)
        V_GOTO( pDevice->CreateUnorderedAccessView( *ppDstTextureAsBufOut, &UAVDesc, &pUAV ) );
        V_GOTO( pDevice->CreateUnorderedAccessView( pErrBestModeBuffer[0], &UAVDesc, &pErrBestModeUAV[0] ) );
        V_GOTO( pDevice->CreateUnorderedAccessView( pErrBestModeBuffer[1], &UAVDesc, &pErrBestModeUAV[1] ) );
#pragma warning (pop)

#if defined(_DEBUG) || defined(PROFILE)
        if ( pUAV )
        {
            pUAV->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 Dest UAV" ) - 1, "BC7 Dest UAV" );
        }
        if ( pErrBestModeUAV[0] )
        {
            pErrBestModeUAV[0]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest0 UAV" ) - 1, "BC7 ErrBest0 UAV" );
        }
        if ( pErrBestModeUAV[1] )
        {
            pErrBestModeUAV[1]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest1 UAV" ) - 1, "BC7 ErrBest1 UAV" );
        }
#endif
    }
    
    {
        D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
        SRVDesc.Buffer.FirstElement = 0;
        SRVDesc.Buffer.NumElements = texSrcDesc.Height * texSrcDesc.Width / BLOCK_SIZE;
        SRVDesc.Format = DXGI_FORMAT_UNKNOWN;
        SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
#pragma warning (push)
#pragma warning (disable:6387)
        V_GOTO( pDevice->CreateShaderResourceView( pErrBestModeBuffer[0], &SRVDesc, &pErrBestModeSRV[0]) );
        V_GOTO( pDevice->CreateShaderResourceView( pErrBestModeBuffer[1], &SRVDesc, &pErrBestModeSRV[1]) );
#pragma warning (pop)

#if defined(_DEBUG) || defined(PROFILE)
        if ( pErrBestModeSRV[0] )
        {
            pErrBestModeSRV[0]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest0 SRV" ) - 1, "BC7 ErrBest0 SRV" );
        }
        if ( pErrBestModeSRV[1] )
        {
            pErrBestModeSRV[1]->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7 ErrBest1 SRV" ) - 1, "BC7 ErrBest1 SRV" );
        }
#endif
    }

    // Create constant buffer    
    {
        D3D11_BUFFER_DESC cbDesc;
        cbDesc.Usage = D3D11_USAGE_DYNAMIC;
        cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
        cbDesc.MiscFlags = 0;
        cbDesc.ByteWidth = sizeof( UINT ) * 8;
        V_GOTO( pDevice->CreateBuffer( &cbDesc, nullptr, &pCBCS ) );

#if defined(_DEBUG) || defined(PROFILE)
        if ( pCBCS )
        {
            pCBCS->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "BC7Encode" ) - 1, "BC7Encode" );
        }
#endif
    }

    int const MAX_BLOCK_BATCH = 64;

    int num_total_blocks = texSrcDesc.Width / BLOCK_SIZE_X * texSrcDesc.Height / BLOCK_SIZE_Y;
    int num_blocks = num_total_blocks;
    int start_block_id = 0;
    while (num_blocks > 0)
    {
        int n = min(num_blocks, MAX_BLOCK_BATCH);
        UINT uThreadGroupCount = n;

        {
            D3D11_MAPPED_SUBRESOURCE cbMapped;
            pContext->Map( pCBCS, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped );

            UINT param[8];
            param[0] = texSrcDesc.Width;
            param[1] = texSrcDesc.Width / BLOCK_SIZE_X;
            param[2] = dstFormat;
            param[3] = 0;
            param[4] = start_block_id;
            param[5] = num_total_blocks;
            *((float*)&param[6]) = m_fAlphaWeight;
            memcpy( cbMapped.pData, param, sizeof( param ) );
            pContext->Unmap( pCBCS, 0 );
        }

        ID3D11ShaderResourceView* pSRVs[] = { pSRV, nullptr };
        RunComputeShader( pContext, m_pTryMode456CS, pSRVs, 2, pCBCS, pErrBestModeUAV[0], __max(uThreadGroupCount / 4, 1), 1, 1 );        

        for (int i = 0; i < 3; ++ i)
        {
            int modes[] = { 1, 3, 7 };
            {
                D3D11_MAPPED_SUBRESOURCE cbMapped;
                pContext->Map( pCBCS, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped );

                UINT param[8];
                param[0] = texSrcDesc.Width;
                param[1] = texSrcDesc.Width / BLOCK_SIZE_X;
                param[2] = dstFormat;
                param[3] = modes[i];
                param[4] = start_block_id;
                param[5] = num_total_blocks;
                *((float*)&param[6]) = m_fAlphaWeight;
                memcpy( cbMapped.pData, param, sizeof( param ) );
                pContext->Unmap( pCBCS, 0 );
            }

            pSRVs[1] = pErrBestModeSRV[i & 1];
            RunComputeShader( pContext, m_pTryMode137CS, pSRVs, 2, pCBCS,  pErrBestModeUAV[!(i & 1)], uThreadGroupCount, 1, 1 );
        }               

        for (int i = 0; i < 2; ++ i)
        {
            int modes[] = { 0, 2 };
            {
                D3D11_MAPPED_SUBRESOURCE cbMapped;
                pContext->Map( pCBCS, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped );

                UINT param[8];
                param[0] = texSrcDesc.Width;
                param[1] = texSrcDesc.Width / BLOCK_SIZE_X;
                param[2] = dstFormat;
                param[3] = modes[i];
                param[4] = start_block_id;
                param[5] = num_total_blocks;
                *((float*)&param[6]) = m_fAlphaWeight;
                memcpy( cbMapped.pData, param, sizeof( param ) );
                pContext->Unmap( pCBCS, 0 );
            }

            pSRVs[1] = pErrBestModeSRV[!(i & 1)];
            RunComputeShader( pContext, m_pTryMode02CS, pSRVs, 2, pCBCS,  pErrBestModeUAV[i & 1], uThreadGroupCount, 1, 1 );
        }

        pSRVs[1] = pErrBestModeSRV[1];
        RunComputeShader( pContext, m_pEncodeBlockCS, pSRVs, 2, pCBCS,  pUAV, __max(uThreadGroupCount / 4, 1), 1, 1 );        

        start_block_id += n;
        num_blocks -= n;
    }

quit:
    SAFE_RELEASE(pSRV);
    SAFE_RELEASE(pUAV);
    SAFE_RELEASE(pErrBestModeSRV[0]);
    SAFE_RELEASE(pErrBestModeSRV[1]);
    SAFE_RELEASE(pErrBestModeUAV[0]);
    SAFE_RELEASE(pErrBestModeUAV[1]);
    SAFE_RELEASE(pErrBestModeBuffer[0]);
    SAFE_RELEASE(pErrBestModeBuffer[1]);
    SAFE_RELEASE(pCBCS);

    return hr;
}
/*++

Routine Name:

    CPTManager::GetMergedTicket

Routine Description:

    This routine retrieves a merged PrintTicket at the requested scope given the base
    and delta PrintTickets as IXMLDOMDocument2 interface pointers

Arguments:

    ptScope  - The scope at which the merge should take place
    pDelta   - The delta PrintTicket as an IXMLDOMDocument2 pointer
    pBase    - The base PrintTicket as an IXMLDOMDocument2 pointer
    ppResult - The resulting PrintTicket after the merge has completed

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPTManager::GetMergedTicket(
    _In_        CONST EPrintTicketScope ptScope,
    _In_        CONST IXMLDOMDocument2* pDelta,
    _In_        IXMLDOMDocument2*       pBase,
    _Outptr_ IXMLDOMDocument2**      ppResult
    )
{
    ASSERTMSG(pDelta != NULL, "NULL PT reference part passed.\n");
    ASSERTMSG(pBase != NULL, "NULL base PT passed.\n");
    ASSERTMSG(ppResult != NULL, "NULL out PT passed.\n");

    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_HANDLE(m_hProvider, E_PENDING)) &&
        SUCCEEDED(hr = CHECK_POINTER(ppResult, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pDelta, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pBase, E_POINTER)))
    {
        *ppResult = NULL;
    }

    CComPtr<IStream> pResultStream(NULL);
    CComPtr<IStream> pBaseStream(NULL);
    CComPtr<IStream> pDeltaStream(NULL);

    CComPtr<IXMLDOMDocument2> pNewPT(NULL);

    //
    // Create a new DOM doc based off the result ticket and
    // assign to the resultant DOM doc
    //
    try
    {
        CComBSTR bstrErrorMessage;

        if (SUCCEEDED(hr) &&
            SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pResultStream)) &&
            SUCCEEDED(hr = pBase->QueryInterface(IID_IStream, reinterpret_cast<VOID**>(&pBaseStream)))  &&
            SUCCEEDED(hr = const_cast<IXMLDOMDocument2*>(pDelta)->QueryInterface(IID_IStream, reinterpret_cast<VOID**>(&pDeltaStream))))
        {
            if (SetThreadToken(NULL, m_hToken))
            {
                if (SUCCEEDED(hr = PTMergeAndValidatePrintTicket(m_hProvider,
                                                                 pBaseStream,
                                                                 pDeltaStream,
                                                                 ptScope,
                                                                 pResultStream,
                                                                 &bstrErrorMessage)))
                {
                    if (SUCCEEDED(hr = SetPTFromStream(pResultStream, &pNewPT)))
                    {
                        //
                        // Assign the outgoing element pointer - detach from CComPtr to release ownership
                        //
                        *ppResult = pNewPT.Detach();
                    }
                }
                else
                {
                    CStringXDA cstrMessage;
                    CStringXDA cstrError(bstrErrorMessage);
                    cstrMessage.Format("PTMergeAndValidatePrintTicket failed with message: %s\n", cstrError);

                    ERR(cstrMessage.GetBuffer());
                }

                //
                // Always revert back to the default security context
                //
                if (!SetThreadToken(NULL, NULL))
                {
                    //
                    // We couldn't revert the security context. The filter pipeline
                    // manager will clean up the thread when operation is complete,
                    // when it is determined that the security context was not 
                    // reverted. Since there are no security implications with 
                    // running this filter in an elevated context, we can 
                    // continue to run.
                    //
                }
            }
            else
            {
                hr = HRESULT_FROM_WIN32(GetLastError());

                //
                // If SetThreadToken fails, GetLastError will return an error
                //
                _Analysis_assume_(FAILED(hr));
            }
        }
    }
    catch (CXDException& e)
    {
        hr = e;
    }

    ERR_ON_HR(hr);
    return hr;
}
Exemple #29
0
VOID
EchoEvtIoWrite(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request,
    IN size_t     Length
    )
/*++

Routine Description:

    This event is invoked when the framework receives IRP_MJ_WRITE request.
    This routine allocates memory buffer, copies the data from the request to it,
    and stores the buffer pointer in the queue-context with the length variable
    representing the buffers length. The actual completion of the request
    is defered to the periodic timer dpc.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length  - number of bytes to be read.
              The default property of the queue is to not dispatch
              zero lenght read & write requests to the driver and
              complete is with status success. So we will never get
              a zero length request.

Return Value:

    VOID

--*/
{
    NTSTATUS Status;
    WDFMEMORY memory;
    PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
    PVOID writeBuffer = NULL;

    _Analysis_assume_(Length > 0);

    KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n",
             Queue,Request,Length));

    if( Length > MAX_WRITE_LENGTH ) {
        KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n",
                 Length,MAX_WRITE_LENGTH));
        WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L);
        return;
    }

    // Get the memory buffer
    Status = WdfRequestRetrieveInputMemory(Request, &memory);
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n",
                 Status));
        WdfVerifierDbgBreakPoint();
        WdfRequestComplete(Request, Status);
        return;
    }

    // Release previous buffer if set
    if( queueContext->WriteMemory != NULL ) {
        WdfObjectDelete(queueContext->WriteMemory);
        queueContext->WriteMemory = NULL;
    }

    Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES,
                             NonPagedPool,
                             'sam1',
                             Length,
                             &queueContext->WriteMemory,
                             &writeBuffer
                             );

    if(!NT_SUCCESS(Status)) {
        KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length));
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }


    // Copy the memory in
    Status = WdfMemoryCopyToBuffer( memory,
                                    0,  // offset into the source memory
                                    writeBuffer,
                                    Length );
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status));
        WdfVerifierDbgBreakPoint();

        WdfObjectDelete(queueContext->WriteMemory);
        queueContext->WriteMemory = NULL;

        WdfRequestComplete(Request, Status);
        return;
    }

    // Set transfer information
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    // Specify the request is cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);

    // Defer the completion to another thread from the timer dpc
    queueContext->CurrentRequest = Request;
    queueContext->CurrentStatus  = Status;

    return;
}
NTSTATUS
TLInspectCloneReinjectInbound(
   _Inout_ TL_INSPECT_PENDED_PACKET* packet
   )
/* ++

   This function clones the inbound net buffer list and, if needed, 
   rebuild the IP header to remove the IpSec headers and receive-injects 
   the clone back to the tcpip stack.

-- */
{
   NTSTATUS status = STATUS_SUCCESS;

   NET_BUFFER_LIST* clonedNetBufferList = NULL;
   NET_BUFFER* netBuffer;
   ULONG nblOffset;
   NDIS_STATUS ndisStatus;

   //
   // For inbound net buffer list, we can assume it contains only one 
   // net buffer.
   //
   netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
   
   nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer);

   //
   // The TCP/IP stack could have retreated the net buffer list by the 
   // transportHeaderSize amount; detect the condition here to avoid
   // retreating twice.
   //
   if (nblOffset != packet->nblOffset)
   {
      NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);
      packet->transportHeaderSize = 0;
   }

   //
   // Adjust the net buffer list offset to the start of the IP header.
   //
   ndisStatus = NdisRetreatNetBufferDataStart(
      netBuffer,
      packet->ipHeaderSize + packet->transportHeaderSize,
      0,
      NULL
      );
   _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);

   //
   // Note that the clone will inherit the original net buffer list's offset.
   //

   status = FwpsAllocateCloneNetBufferList(
               packet->netBufferList,
               NULL,
               NULL,
               0,
               &clonedNetBufferList
               );

   //
   // Undo the adjustment on the original net buffer list.
   //

   NdisAdvanceNetBufferDataStart(
      netBuffer,
      packet->ipHeaderSize + packet->transportHeaderSize,
      FALSE,
      NULL
      );

   if (!NT_SUCCESS(status))
   {
      goto Exit;
   }

   if (packet->ipSecProtected)
   {
      //
      // When an IpSec protected packet is indicated to AUTH_RECV_ACCEPT or 
      // INBOUND_TRANSPORT layers, for performance reasons the tcpip stack
      // does not remove the AH/ESP header from the packet. And such 
      // packets cannot be recv-injected back to the stack w/o removing the
      // AH/ESP header. Therefore before re-injection we need to "re-build"
      // the cloned packet.
      // 
      status = FwpsConstructIpHeaderForTransportPacket(
                  clonedNetBufferList,
                  packet->ipHeaderSize,
                  packet->addressFamily,
                  (UINT8*)&packet->remoteAddr, 
                  (UINT8*)&packet->localAddr,  
                  packet->protocol,
                  0,
                  NULL,
                  0,
                  0,
                  NULL,
                  0,
                  0
                  );

      if (!NT_SUCCESS(status))
      {
         goto Exit;
      }
   }

   if (packet->completionContext != NULL)
   {
      NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);

      FwpsCompleteOperation(
         packet->completionContext,
         clonedNetBufferList
         );

      packet->completionContext = NULL;
   }

   status = FwpsInjectTransportReceiveAsync(
               gInjectionHandle,
               NULL,
               NULL,
               0,
               packet->addressFamily,
               packet->compartmentId,
               packet->interfaceIndex,
               packet->subInterfaceIndex,
               clonedNetBufferList,
               TLInspectInjectComplete,
               packet
               );

   if (!NT_SUCCESS(status))
   {
      goto Exit;
   }

   clonedNetBufferList = NULL; // ownership transferred to the 
                               // completion function.

Exit:

   if (clonedNetBufferList != NULL)
   {
      FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
   }

   return status;
}