コード例 #1
0
ファイル: tl_drv.c プロジェクト: pboy0922/afdmjhk
VOID
DriverUnload(
    IN  PDRIVER_OBJECT driverObject
)
{
    NTSTATUS status;
    PVOID threadObj;

    KLOCK_QUEUE_HANDLE connListLockHandle;
    KLOCK_QUEUE_HANDLE packetQueueLockHandle;

    UNREFERENCED_PARAMETER(driverObject);

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

    gDriverUnloading = TRUE;

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

    if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue))
    {
        KeSetEvent(
            &gWorkerEvent,
            IO_NO_INCREMENT,
            FALSE
        );
    }

    ASSERT(gThreadObj != NULL);

    KeWaitForSingleObject(
        gThreadObj,
        Executive,
        KernelMode,
        FALSE,
        NULL
    );

    ObDereferenceObject(gThreadObj);

    TLInspectUnregisterCallouts();

    FwpsInjectionHandleDestroy0(gInjectionHandle);

    IoDeleteDevice(gDeviceObject);

    ZwClose(gRegistryKey);
}
コード例 #2
0
ファイル: ioctl.c プロジェクト: xenclient-project/legacy-v4v
static NTSTATUS
V4vCtrlGetInfo(XENV4V_CONTEXT *ctx, V4V_GETINFO_VALUES *gi)
{
    NTSTATUS           status = STATUS_INVALID_DEVICE_REQUEST;
    LONG               val;
    KLOCK_QUEUE_HANDLE lqh;

    val = InterlockedExchangeAdd(&ctx->state, 0);

    if (gi->type == V4vGetPeerInfo) {
        if (val & (XENV4V_STATE_CONNECTING|XENV4V_STATE_CONNECTED|XENV4V_STATE_ACCEPTED)) {
            RtlMoveMemory(&gi->ringInfo.addr, &ctx->sdst, sizeof(v4v_addr_t));
            gi->ringInfo.partner = V4V_DOMID_NONE;
            status = STATUS_SUCCESS;
        }
    }
    else if (gi->type == V4vGetLocalInfo) {
        if (val & (XENV4V_STATE_BOUND|XENV4V_STATE_LISTENING|XENV4V_STATE_WAITING|
                   XENV4V_STATE_CONNECTING|XENV4V_STATE_CONNECTED|
                   XENV4V_STATE_ACCEPTED)) {
            KeAcquireInStackQueuedSpinLock(&ctx->ringObject->lock, &lqh);
            RtlMoveMemory(&gi->ringInfo, &ctx->ringObject->ring->id, sizeof(v4v_ring_id_t));
            KeReleaseInStackQueuedSpinLock(&lqh);
            status = STATUS_SUCCESS;
        }
    }
    
    return status;
}
コード例 #3
0
NTSTATUS
MonitorCoInsertFlowContext(
   _Inout_ FLOW_DATA* flowContext)
{
   KLOCK_QUEUE_HANDLE lockHandle;
   NTSTATUS status;

   KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);

   // Catch the case where we disabled monitoring after we had intended to
   // associate the context to the flow so that we don't bugcheck due to
   // our driver being unloaded and then receiving a call for a particular
   // flow or leak the memory because we unloaded without freeing it.
   if (monitoringEnabled)
   {
      DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Creating flow for traffic.\r\n");

      InsertTailList(&flowContextList, &flowContext->listEntry);
      status = STATUS_SUCCESS;
   }
   else
   {
      DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Unable to create flow, driver shutting down.\r\n");

      // Our driver is shutting down.
      status = STATUS_SHUTDOWN_IN_PROGRESS;
   }

   KeReleaseInStackQueuedSpinLock(&lockHandle);
   return status;
}
コード例 #4
0
ファイル: callout.c プロジェクト: Rootkitsmm/windbgshark
NTSTATUS drvStreamDeletion(
	IN  UINT16 layerId,
	IN  UINT32 calloutId,
	IN  UINT64 flowContext)
{
	// We can't free the memory of the corresponding FLOW_DATA 
	// disposition here, while thAnalyzer thread may use it. Stream 
	// deletion is handled in the thAnalyzer thread, while processing
	// the "close" packet, which is sent from here

	KLOCK_QUEUE_HANDLE packetQueueLockHandle;
	PENDED_PACKET *pendedPacket;
	BOOLEAN signalWorkerThread;

	// pendedPacket gets deleted in FreePendedPacket
	#pragma warning( suppress : 28197 )
	pendedPacket = ExAllocatePoolWithTag(
		NonPagedPool,
		sizeof(PENDED_PACKET),
		TAG_PENDEDPACKET);

	if (pendedPacket == NULL)
	{
		return STATUS_UNSUCCESSFUL;
	}

	RtlZeroMemory(pendedPacket, sizeof(PENDED_PACKET));

	pendedPacket->flowContext = (FLOW_DATA *) flowContext;
	pendedPacket->close = TRUE;

	KeAcquireInStackQueuedSpinLock(
		&gPacketQueueLock,
		&packetQueueLockHandle);

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

		InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
		pendedPacket = NULL; // ownership transferred
	}
	else
	{
		// Driver is being unloaded, permit any connect classify.
		signalWorkerThread = FALSE;
	}

	KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);

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

	return STATUS_SUCCESS;
}
コード例 #5
0
ファイル: xenv4v.c プロジェクト: meisners/oxt-windows
static NTSTATUS
V4vInitializeEventChannel(PDEVICE_OBJECT fdo)
{
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    KLOCK_QUEUE_HANDLE  lqh;

    KeAcquireInStackQueuedSpinLock(&pde->virqLock, &lqh);

    if (!is_null_EVTCHN_PORT(pde->virqPort)) {
        KeReleaseInStackQueuedSpinLock(&lqh);
        TraceWarning(("V4V VIRQ already bound?\n"));
	    return STATUS_SUCCESS;
    }

    pde->virqPort = EvtchnBindVirq(VIRQ_V4V, V4vVirqNotifyIsr, fdo);
    if (is_null_EVTCHN_PORT(pde->virqPort)) {
        KeReleaseInStackQueuedSpinLock(&lqh);
        TraceError(("failed to bind V4V VIRQ\n"));
	    return STATUS_INSUFFICIENT_RESOURCES;
    }

    KeReleaseInStackQueuedSpinLock(&lqh);

    TraceNotice(("V4V VIRQ connected.\n"));

    return STATUS_SUCCESS;
}
コード例 #6
0
ファイル: log.cpp プロジェクト: JulianVolodia/HyperPlatform
// Switchs the current log buffer, saves the contents of old buffer to the log
// file, and prints them out as necessary. This function does not flush the log
// file, so code should call LogpWriteMessageToFile() or ZwFlushBuffersFile()
// later.
_Use_decl_annotations_ static NTSTATUS LogpFlushLogBuffer(LogBufferInfo *info) {
  NT_ASSERT(info);
  NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

  auto status = STATUS_SUCCESS;

  // Enter a critical section and acquire a reader lock for info in order to
  // write a log file safely.
  ExEnterCriticalRegionAndAcquireResourceExclusive(&info->resource);

  // Acquire a spin lock for info.log_buffer(s) in order to switch its head
  // safely.
  KLOCK_QUEUE_HANDLE lock_handle = {};
  KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle);
  const auto old_log_buffer = const_cast<char *>(info->log_buffer_head);
  if (old_log_buffer[0]) {
    info->log_buffer_head = (old_log_buffer == info->log_buffer1)
                                ? info->log_buffer2
                                : info->log_buffer1;
    info->log_buffer_head[0] = '\0';
    info->log_buffer_tail = info->log_buffer_head;
  }
  KeReleaseInStackQueuedSpinLock(&lock_handle);

  // Write all log entries in old log buffer.
  IO_STATUS_BLOCK io_status = {};
  for (auto current_log_entry = old_log_buffer; current_log_entry[0]; /**/) {
    // Check the printed bit and clear it
    const auto printed_out = LogpIsPrinted(current_log_entry);
    LogpSetPrintedBit(current_log_entry, false);

    const auto current_log_entry_length = strlen(current_log_entry);
    status = ZwWriteFile(info->log_file_handle, nullptr, nullptr, nullptr,
                         &io_status, current_log_entry,
                         static_cast<ULONG>(current_log_entry_length), nullptr,
                         nullptr);
    if (!NT_SUCCESS(status)) {
      // It could happen when you did not register IRP_SHUTDOWN and call
      // LogIrpShutdownHandler() and the system tried to log to a file after
      // a file system was unmounted.
      LogpDbgBreak();
    }

    // Print it out if requested and the message is not already printed out
    if (!printed_out) {
      LogpDoDbgPrint(current_log_entry);
    }

    current_log_entry += current_log_entry_length + 1;
  }
  old_log_buffer[0] = '\0';

  ExReleaseResourceAndLeaveCriticalRegion(&info->resource);
  return status;
}
コード例 #7
0
VOID DriverUnload(
	IN  PDRIVER_OBJECT driverObject)
{
	UNICODE_STRING dosDeviceName;
	UNREFERENCED_PARAMETER(driverObject);

	// set the unloading marker
	{
		KLOCK_QUEUE_HANDLE packetQueueLockHandle;
		KeAcquireInStackQueuedSpinLock(
			&gPacketQueueLock,
			&packetQueueLockHandle
			);

		gDriverUnloading = TRUE;

		KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
	}

	CleanupFlowContextList();

	if (IsListEmpty(&gPacketQueue))
	{
		KeSetEvent(
			&gWorkerEvent,
			IO_NO_INCREMENT, 
			FALSE);
	}

	ASSERT(gThreadObj != NULL);

	KeWaitForSingleObject(
		gThreadObj,
		Executive,
		KernelMode,
		FALSE,
		NULL);

	ObDereferenceObject(gThreadObj);

	UnregisterCallouts();

	NdisFreeNetBufferListPool(gNetBufferListPool);
	NdisFreeGenericObject(gNdisGenericObj);

	FwpsInjectionHandleDestroy0(gInjectionHandle);

	RtlInitUnicodeString(&dosDeviceName, SYMBOLIC_LINK_NAME);
	IoDeleteSymbolicLink(&dosDeviceName);

	IoDeleteDevice(gDeviceObject);
}
コード例 #8
0
ファイル: xenv4v.c プロジェクト: meisners/oxt-windows
VOID
V4vStartConnectionTimer(XENV4V_EXTENSION *pde)
{
    KLOCK_QUEUE_HANDLE lqh;
    ULONG              count;
    LARGE_INTEGER      due;

    KeAcquireInStackQueuedSpinLock(&pde->timerLock, &lqh);    
    count = ++pde->timerCounter;
    KeReleaseInStackQueuedSpinLock(&lqh);

    // Just transitioned from 1
    if (count == 1) {
        due.QuadPart = XENV4V_LARGEINT_DELAY(XENV4V_TIMER_INTERVAL/2);
        KeSetTimerEx(&pde->timer, due, XENV4V_TIMER_INTERVAL, &pde->timerDpc);
    }
}
コード例 #9
0
void
OobEditShutdown(
   _Out_ STREAM_EDITOR* streamEditor
   )
{
   KLOCK_QUEUE_HANDLE editLockHandle;

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

   streamEditor->oobEditInfo.shuttingDown = TRUE;

   switch (streamEditor->oobEditInfo.editState)
   {
      case OOB_EDIT_IDLE:
      {
         streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;

         KeSetEvent(
            &gStreamEditor.oobEditInfo.editEvent,
            IO_NO_INCREMENT, 
            FALSE
            );

         break;
      }
      default:
         break;
   };

   KeReleaseInStackQueuedSpinLock(&editLockHandle);

   NT_ASSERT(gThreadObj != NULL);

   KeWaitForSingleObject(
      gThreadObj,
      Executive,
      KernelMode,
      FALSE,
      NULL
      );

   ObDereferenceObject(gThreadObj);
}
コード例 #10
0
ファイル: DD_drv.c プロジェクト: kcrazy/winekit
void
DDProxyRemoveFlows()
{
   while (!IsListEmpty(&gFlowList))
   {
      KLOCK_QUEUE_HANDLE flowListLockHandle;
      LIST_ENTRY* listEntry = NULL;
      DD_PROXY_FLOW_CONTEXT* flowContext;

      KeAcquireInStackQueuedSpinLock(
         &gFlowListLock,
         &flowListLockHandle
         );

      if (!IsListEmpty(&gFlowList))
      {
         listEntry = RemoveHeadList(&gFlowList);
      }

      //
      // Releasing the lock here since removing the flow context 
      // will invoke the callout's flowDeleteFn synchronously 
      // if there are no active classifications in progress.
      //
      KeReleaseInStackQueuedSpinLock(&flowListLockHandle);

      if (listEntry != NULL)
      {
         flowContext = CONTAINING_RECORD(
                           listEntry,
                           DD_PROXY_FLOW_CONTEXT,
                           listEntry
                           );

         flowContext->deleted = TRUE;

         FwpsFlowRemoveContext0(
            flowContext->flowId,
            flowContext->layerId,
            flowContext->calloutId
            );
      }
   }
}
コード例 #11
0
RBOOL
    task_get_new_processes
    (
        RPU8 pArgs,
        RU32 argsSize,
        RPU8 pResult,
        RU32* resultSize
    )
{
    RBOOL isSuccess = FALSE;
    KLOCK_QUEUE_HANDLE hMutex = { 0 };

    RU32 toCopy = 0;

    UNREFERENCED_PARAMETER( pArgs );
    UNREFERENCED_PARAMETER( argsSize );

    if( NULL != pResult &&
        NULL != resultSize &&
        0 != *resultSize )
    {
        KeAcquireInStackQueuedSpinLock( &g_collector_1_mutex, &hMutex );

        toCopy = ( *resultSize ) / sizeof( KernelAcqProcess );

        if( 0 != toCopy )
        {
            toCopy = ( toCopy > g_nextProcess ? g_nextProcess : toCopy );

            *resultSize = toCopy * sizeof( KernelAcqProcess );
            memcpy( pResult, g_processes, *resultSize );

            g_nextProcess -= toCopy;
            memmove( g_processes, g_processes + toCopy, g_nextProcess );
        }

        KeReleaseInStackQueuedSpinLock( &hMutex );

        isSuccess = TRUE;
    }

    return isSuccess;
}
コード例 #12
0
ファイル: ioctl.c プロジェクト: xenclient-project/legacy-v4v
static NTSTATUS
V4vCtrlDumpRing(XENV4V_CONTEXT *ctx)
{
    NTSTATUS           status = STATUS_INVALID_DEVICE_REQUEST;
    LONG               val;
    KLOCK_QUEUE_HANDLE lqh;

    val = InterlockedExchangeAdd(&ctx->state, 0);

    if (val & (XENV4V_STATE_BOUND|XENV4V_STATE_LISTENING|XENV4V_STATE_WAITING|
               XENV4V_STATE_CONNECTING|XENV4V_STATE_CONNECTED|
               XENV4V_STATE_ACCEPTED)) {
        KeAcquireInStackQueuedSpinLock(&ctx->ringObject->lock, &lqh);
        V4vDumpRing(ctx->ringObject->ring);
        KeReleaseInStackQueuedSpinLock(&lqh);
        status = STATUS_SUCCESS;
    }
    
    return status;
}
コード例 #13
0
ファイル: xenv4v.c プロジェクト: meisners/oxt-windows
VOID
V4vStopConnectionTimer(XENV4V_EXTENSION *pde, BOOLEAN immediate)
{
    KLOCK_QUEUE_HANDLE lqh;
    ULONG              count = (ULONG)-1;

    KeAcquireInStackQueuedSpinLock(&pde->timerLock, &lqh);
    if (immediate) {
        count = pde->timerCounter = 0;
    }
    else if (pde->timerCounter > 0) {
        count = --pde->timerCounter;
    }
    KeReleaseInStackQueuedSpinLock(&lqh);

    // Dropped back to 0, turn off the timer
    if (count == 0) {
        KeCancelTimer(&pde->timer);
    }
}
コード例 #14
0
BOOLEAN
ImScsiVirtualDrivesPresent()
{
    PLIST_ENTRY           list_ptr;
    BOOLEAN		  result = FALSE;

#if defined(_AMD64_)
    KLOCK_QUEUE_HANDLE    LockHandle;
    KeAcquireInStackQueuedSpinLock(                   // Serialize the linked list of HBA.
        &pMPDrvInfoGlobal->DrvInfoLock, &LockHandle);
#else
    KIRQL                 SaveIrql;
    KeAcquireSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &SaveIrql);
#endif

    for (list_ptr = pMPDrvInfoGlobal->ListMPHBAObj.Flink;
        list_ptr != &pMPDrvInfoGlobal->ListMPHBAObj;
        list_ptr = list_ptr->Flink
        )
    {
        pHW_HBA_EXT pHBAExt;

        pHBAExt = CONTAINING_RECORD(list_ptr, HW_HBA_EXT, List);

        if (!IsListEmpty(&pHBAExt->LUList))
        {
            result = TRUE;
            break;
        }
    }

    pMPDrvInfoGlobal->DrvInfoLock;

#if defined(_AMD64_)
    KeReleaseInStackQueuedSpinLock(&LockHandle);
#else
    KeReleaseSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, SaveIrql);
#endif

    return result;
}
コード例 #15
0
ファイル: xenv4v.c プロジェクト: meisners/oxt-windows
static VOID
V4vUninitializeEventChannel(PDEVICE_OBJECT fdo)
{
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    KLOCK_QUEUE_HANDLE  lqh;

    KeAcquireInStackQueuedSpinLock(&pde->virqLock, &lqh);

    if (is_null_EVTCHN_PORT(pde->virqPort)) {
        // This is ok, e.g. getting a stop and remove PnP call
        KeReleaseInStackQueuedSpinLock(&lqh);
	    return;
    }

    EvtchnClose(pde->virqPort);
    pde->virqPort = null_EVTCHN_PORT();

    KeReleaseInStackQueuedSpinLock(&lqh);

    TraceNotice(("V4V VIRQ disconnected.\n"));
}
コード例 #16
0
VOID
MpHwFreeAdapterResources(__in pHW_HBA_EXT pHBAExt)
{
    PLIST_ENTRY           pNextEntry; 
    pHW_HBA_EXT           pLclHBAExt;
#if defined(_AMD64_)
    KLOCK_QUEUE_HANDLE    LockHandle;
#else
    KIRQL                 SaveIrql;
#endif

    KdPrint2(("PhDskMnt::MpHwFreeAdapterResources:  pHBAExt = 0x%p\n", pHBAExt));

#if defined(_AMD64_)
    KeAcquireInStackQueuedSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &LockHandle);
#else
    KeAcquireSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &SaveIrql);
#endif

    for (                                             // Go through linked list of HBA extensions.
         pNextEntry =  pMPDrvInfoGlobal->ListMPHBAObj.Flink;
         pNextEntry != &pMPDrvInfoGlobal->ListMPHBAObj;
         pNextEntry =  pNextEntry->Flink
        ) {
        pLclHBAExt = CONTAINING_RECORD(pNextEntry, HW_HBA_EXT, List);

        if (pLclHBAExt==pHBAExt) {                    // Is this entry the same as pHBAExt?
            RemoveEntryList(pNextEntry);
            pMPDrvInfoGlobal->DrvInfoNbrMPHBAObj--;
            break;
        }
    }

#if defined(_AMD64_)
    KeReleaseInStackQueuedSpinLock(&LockHandle);
#else
    KeReleaseSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, SaveIrql);
#endif

}                                                     // End MpHwFreeAdapterResources().
コード例 #17
0
ファイル: log.cpp プロジェクト: JulianVolodia/HyperPlatform
// Buffer the log entry to the log buffer.
_Use_decl_annotations_ static NTSTATUS LogpBufferMessage(const char *message,
                                                         LogBufferInfo *info) {
  NT_ASSERT(info);

  // Acquire a spin lock to add the log safely.
  KLOCK_QUEUE_HANDLE lock_handle = {};
  const auto old_irql = KeGetCurrentIrql();
  if (old_irql < DISPATCH_LEVEL) {
    KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle);
  } else {
    KeAcquireInStackQueuedSpinLockAtDpcLevel(&info->spin_lock, &lock_handle);
  }
  NT_ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);

  // Copy the current log to the buffer.
  SIZE_T used_buffer_size = info->log_buffer_tail - info->log_buffer_head;
  auto status =
      RtlStringCchCopyA(const_cast<char *>(info->log_buffer_tail),
                        kLogpBufferUsableSize - used_buffer_size, message);

  // Update info.log_max_usage if necessary.
  if (NT_SUCCESS(status)) {
    const auto message_length = strlen(message) + 1;
    info->log_buffer_tail += message_length;
    used_buffer_size += message_length;
    if (used_buffer_size > info->log_max_usage) {
      info->log_max_usage = used_buffer_size;  // Update
    }
  } else {
    info->log_max_usage = kLogpBufferSize;  // Indicates overflow
  }
  *info->log_buffer_tail = '\0';

  if (old_irql < DISPATCH_LEVEL) {
    KeReleaseInStackQueuedSpinLock(&lock_handle);
  } else {
    KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_handle);
  }
  return status;
}
コード例 #18
0
static VOID
    CreateProcessNotifyEx
    (
        PEPROCESS Process,
        HANDLE ProcessId,
        PPS_CREATE_NOTIFY_INFO CreateInfo
    )
{
    KLOCK_QUEUE_HANDLE hMutex = { 0 };

    UNREFERENCED_PARAMETER( Process );

    KeAcquireInStackQueuedSpinLock( &g_collector_1_mutex, &hMutex );

    
    // We're only interested in starts for now, a non-NULL CreateInfo indicates this.
    if( NULL != CreateInfo )
    {
        g_processes[ g_nextProcess ].pid = (RU32)ProcessId;
        g_processes[ g_nextProcess ].ppid = (RU32)CreateInfo->ParentProcessId;
        g_processes[ g_nextProcess ].ts = rpal_time_getLocal();
        g_processes[ g_nextProcess ].uid = KERNEL_ACQ_NO_USER_ID;

        copyUnicodeStringToBuffer( CreateInfo->ImageFileName, 
                                   g_processes[ g_nextProcess ].path );

        copyUnicodeStringToBuffer( CreateInfo->CommandLine,
                                   g_processes[ g_nextProcess ].cmdline );

        g_nextProcess++;
        if( g_nextProcess == _NUM_BUFFERED_PROCESSES )
        {
            g_nextProcess = 0;
        }
    }

    KeReleaseInStackQueuedSpinLock( &hMutex );
}
コード例 #19
0
NTSTATUS
StreamOobFlushOutgoingData(
   _Inout_ STREAM_EDITOR* streamEditor
   )
{
   NTSTATUS status = STATUS_SUCCESS;

   KLOCK_QUEUE_HANDLE editLockHandle;
   OUTGOING_STREAM_DATA* outgoingStreamData = NULL;

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

      if (!IsListEmpty(&streamEditor->oobEditInfo.outgoingDataQueue))
      {
         LIST_ENTRY* listEntry = 
            RemoveHeadList(&streamEditor->oobEditInfo.outgoingDataQueue);
         
         outgoingStreamData = CONTAINING_RECORD(
                                 listEntry, 
                                 OUTGOING_STREAM_DATA,
                                 listEntry
                                 );
      }

      KeReleaseInStackQueuedSpinLock(&editLockHandle);

      if (outgoingStreamData == NULL)
      {
         break;
      }

      status = FwpsStreamInjectAsync(
                  gInjectionHandle,
                  NULL,
                  0,
                  streamEditor->oobEditInfo.flowId,
                  streamEditor->oobEditInfo.calloutId,
                  streamEditor->oobEditInfo.layerId,
                  outgoingStreamData->streamFlags,
                  outgoingStreamData->netBufferList,
                  outgoingStreamData->dataLength,
                  outgoingStreamData->isClone ? StreamOobInjectCloneCompletionFn :
                                                StreamOobInjectCompletionFn,
                  outgoingStreamData->mdl
                  );

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

      ExFreePoolWithTag(
         outgoingStreamData,
         STREAM_EDITOR_OUTGOING_DATA_TAG
         );

      outgoingStreamData = NULL;
   }
  
Exit:

   if (outgoingStreamData != NULL)
   {
      NT_ASSERT(!NT_SUCCESS(status));

      if (outgoingStreamData->isClone)
      {
         FwpsDiscardClonedStreamData(
            outgoingStreamData->netBufferList,
            0,
            FALSE
            );
      }
      else
      {
         FwpsFreeNetBufferList(outgoingStreamData->netBufferList);

         if (outgoingStreamData->mdl != NULL)
         {
            IoFreeMdl(outgoingStreamData->mdl);

            ExFreePoolWithTag(
               outgoingStreamData->mdl->MappedSystemVa, 
               STREAM_EDITOR_MDL_DATA_TAG
               );
         }
      }

      ExFreePoolWithTag(
         outgoingStreamData,
         STREAM_EDITOR_OUTGOING_DATA_TAG
         );
   }

   return status;
}
コード例 #20
0
NTSTATUS
StreamOobQueueUpOutgoingData(
   _Inout_ STREAM_EDITOR* streamEditor,
   _Inout_ NET_BUFFER_LIST* netBufferList,
   BOOLEAN isClone,
   size_t dataLength,
   DWORD streamFlags,
   _In_opt_ MDL* mdl
   )
/* ++

   This function queues up processed data (either sections of the indicated
   data or newly created data) such that they can be (re-)injected back to
   the data stream during the following context.

      1. Before FWP_ACTION_BLOCK is returned from the ClassifyFn, or
      2. After EOF is indicated.

   Under the conditions above, the incoming data (which we pend) and the 
   outgoing data (which we (re-)inject) can be synchronized properly).

-- */
{
   NTSTATUS status = STATUS_SUCCESS;
   KLOCK_QUEUE_HANDLE editLockHandle;
   OUTGOING_STREAM_DATA* outgoingStreamData;

   outgoingStreamData = (OUTGOING_STREAM_DATA*) ExAllocatePoolWithTag(
                                                   NonPagedPool,
                                                   sizeof(OUTGOING_STREAM_DATA),
                                                   STREAM_EDITOR_OUTGOING_DATA_TAG
                                                   );

   if (outgoingStreamData == NULL)
   {
      status = STATUS_NO_MEMORY;
      return status;
   }

   RtlZeroMemory(outgoingStreamData, sizeof(OUTGOING_STREAM_DATA));

   outgoingStreamData->netBufferList = netBufferList;
   outgoingStreamData->isClone = isClone;
   outgoingStreamData->dataLength = dataLength;
   outgoingStreamData->streamFlags = streamFlags;
   outgoingStreamData->mdl = mdl;

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

   InsertTailList(
      &streamEditor->oobEditInfo.outgoingDataQueue,
      &outgoingStreamData->listEntry
      );

   KeReleaseInStackQueuedSpinLock(&editLockHandle);

   return status;
}
コード例 #21
0
void
StreamOobEdit(
   _Inout_ STREAM_EDITOR* streamEditor,
   const FWPS_INCOMING_VALUES* inFixedValues,
   const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
   const FWPS_FILTER* filter,
   _Inout_ FWPS_STREAM_DATA* streamData,
   _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket,
   _Inout_ FWPS_CLASSIFY_OUT* classifyOut
   )
/* ++

   This function queues up incoming data and notifies the worker thread
   to process them. The incoming data is blocked and removed from the
   stream while data is pending.

   If the editor is shutdown (e.g. during driverUnload) as indicated 
   by OOB_EDIT_SHUT_DOWN state, it permits the indicated data inline after 
   flushing all pended data (to be carried out by the caller).

-- */

{
   NTSTATUS status;

   KLOCK_QUEUE_HANDLE editLockHandle;

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

   if (streamEditor->oobEditInfo.nblEof != NULL)
   {
      //
      // A new flow arrives before we finish processing an earlier flow. Production
      // code should create 1:1 between streamEditor and flow to handle this
      // condition. See the "MSN Monitor sample" for how that can be implemented. 
      //

      ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
      classifyOut->actionType = FWP_ACTION_NONE;

      goto Exit;
   }

   if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)
   {
      NT_ASSERT(streamEditor->oobEditInfo.nblEof == NULL);

      streamEditor->oobEditInfo.noMoreData = TRUE;
   }

   // 
   // Record needed flow information etc for data (re-)injection.
   //

   streamEditor->oobEditInfo.calloutId = filter->action.calloutId;
   streamEditor->oobEditInfo.flowId = inMetaValues->flowHandle;
   streamEditor->oobEditInfo.layerId = inFixedValues->layerId;

   switch (streamEditor->oobEditInfo.editState)
   {
      case OOB_EDIT_PROCESSING:
      {
         if ((streamEditor->oobEditInfo.totalDataLength + streamData->dataLength) > 
            streamEditor->oobEditInfo.busyThreshold)
         {
            ioPacket->streamAction = FWPS_STREAM_ACTION_DEFER;
            classifyOut->actionType = FWP_ACTION_NONE;

            streamEditor->oobEditInfo.editState = OOB_EDIT_BUSY;
         }
         else
         {
            status = StreamOobQueueUpIncomingData(
                        streamEditor,
                        streamData
                        );

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

               ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
               classifyOut->actionType = FWP_ACTION_NONE;
            }
            else
            {
               //
               // State remains at OOB_EDIT_PROCESSING state. Since the worker thread
               // is active there is no need to set the event (to wake it up)
               //

               ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
               ioPacket->countBytesEnforced = 0;
               classifyOut->actionType = FWP_ACTION_BLOCK;
               classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            }
         }

         break;
      }
      case OOB_EDIT_IDLE:
      {
         status = StreamOobQueueUpIncomingData(
                     streamEditor,
                     streamData
                     );

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

            ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
            classifyOut->actionType = FWP_ACTION_NONE;
         }
         else
         {
            streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;

            //
            // The worker thread is idle waiting for more work, now wake it up.
            //
            KeSetEvent(
               &streamEditor->oobEditInfo.editEvent, 
               0, 
               FALSE
               );

            ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
            ioPacket->countBytesEnforced = 0;
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         }

         break;
      }
      case OOB_EDIT_SHUT_DOWN:
      {
         ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
         ioPacket->countBytesEnforced = 0;
         classifyOut->actionType = FWP_ACTION_PERMIT;

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

         break;
      }
      case OOB_EDIT_ERROR:
      {
         ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
         classifyOut->actionType = FWP_ACTION_NONE;
         break;
      }
      default:
         NT_ASSERT(FALSE);
   };

Exit:

   KeReleaseInStackQueuedSpinLock(&editLockHandle);
}
コード例 #22
0
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);
}
コード例 #23
0
ファイル: inspect.c プロジェクト: kcrazy/winekit
void
TLInspectTransportClassify(
   IN const FWPS_INCOMING_VALUES0* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
   IN OUT void* layerData,
   IN const FWPS_FILTER0* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT0* classifyOut
   )
/* ++

   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;

   UNREFERENCED_PARAMETER(flowContext);
   UNREFERENCED_PARAMETER(filter);   

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

  ASSERT(layerData != NULL);

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

   if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
       (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
   {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      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;
         goto Exit;
      }
      else
      {
         //
         // To be compatible with Vista's IpSec implementation, we must not
         // intercept not-yet-detunneled IpSec traffic.
         //
         FWPS_PACKET_LIST_INFORMATION0 packetInfo = {0};
         FwpsGetPacketListSecurityInformation0(
            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;
            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->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
   }
   else
   {
      //
      // Driver is being unloaded, permit any connect classify.
      //
      signalWorkerThread = FALSE;

      classifyOut->actionType = FWP_ACTION_PERMIT;
   }

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

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

Exit:

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

   return;
}
コード例 #24
0
ファイル: inspect.c プロジェクト: kcrazy/winekit
void
TLInspectWorker(
   IN PVOID 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))
      {
         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)
      {
         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);
   }

   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);
         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);

}
コード例 #25
0
ファイル: devquobj.c プロジェクト: AlexiaChen/wrk_study
BOOLEAN
KeRemoveEntryDeviceQueue (
    __inout PKDEVICE_QUEUE DeviceQueue,
    __inout PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
    )

/*++

Routine Description:

    This function removes a specified entry from the the specified device
    queue. If the device queue entry is not in the device queue, then no
    operation is performed. Otherwise the specified device queue entry is
    removed from the device queue and its inserted status is set to FALSE.

Arguments:

    DeviceQueue - Supplies a pointer to a control object of type device queue.

    DeviceQueueEntry - Supplies a pointer to a device queue entry which is to
        be removed from its device queue.

Return Value:

    A value of TRUE is returned if the device queue entry is removed from its
    device queue. Otherwise a value of FALSE is returned.

--*/

{

    KLOCK_QUEUE_HANDLE LockHandle;
    BOOLEAN Removed;

    ASSERT_DEVICE_QUEUE(DeviceQueue);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock specified device queue.
    //

    KeAcquireInStackQueuedSpinLock(&DeviceQueue->Lock, &LockHandle);

    //
    // If the device queue entry is not in a device queue, then no operation
    // is performed. Otherwise remove the specified device queue entry from its
    // device queue.
    //

    Removed = DeviceQueueEntry->Inserted;
    if (Removed == TRUE) {
        DeviceQueueEntry->Inserted = FALSE;
        RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
        KiInvalidateDeviceQueueKeyHint(DeviceQueue,DeviceQueueEntry);
    }

    //
    // Unlock specified device queue, lower IRQL to its previous level, and
    // return whether the device queue entry was removed from its queue.
    //

    KeReleaseInStackQueuedSpinLock(&LockHandle);
    return Removed;
}
コード例 #26
0
ファイル: DD_drv.c プロジェクト: kcrazy/winekit
VOID
DriverUnload(
   IN  PDRIVER_OBJECT driverObject
   )
{
   NTSTATUS status;
   PVOID threadObj;

   KLOCK_QUEUE_HANDLE packetQueueLockHandle;
   KLOCK_QUEUE_HANDLE flowListLockHandle;

   UNREFERENCED_PARAMETER(driverObject);
   UNREFERENCED_PARAMETER(status);
   UNREFERENCED_PARAMETER(threadObj);

   KeAcquireInStackQueuedSpinLock(
      &gPacketQueueLock,
      &packetQueueLockHandle
      );

   KeAcquireInStackQueuedSpinLock(
      &gFlowListLock,
      &flowListLockHandle
      );

   gDriverUnloading = TRUE;

   KeReleaseInStackQueuedSpinLock(&flowListLockHandle);

   //
   // Any associated flow contexts must be removed before
   // a callout can be successfully unregistered.
   //
   DDProxyRemoveFlows();

   if (IsListEmpty(&gPacketQueue))
   {
      KeSetEvent(
         &gPacketQueueEvent,
         IO_NO_INCREMENT, 
         FALSE
         );
   }

   KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);

   ASSERT(gThreadObj != NULL);

   KeWaitForSingleObject(
      gThreadObj,
      Executive,
      KernelMode,
      FALSE,
      NULL
      );

   ObDereferenceObject(gThreadObj);

   DDProxyUnregisterCallouts();

   FwpsInjectionHandleDestroy0(gInjectionHandle);

   IoDeleteDevice(gDeviceObject);
}
コード例 #27
0
ULONG
MpHwFindAdapter(
                __in       PVOID                           DeviceExtension,
                __in       PVOID                           pReservedArg1,
                __in       PVOID                           pReservedArg2,
#ifdef USE_STORPORT
                __in       PVOID                           pReservedArg3,
#endif
                __in       PCHAR                           ArgumentString,
                __in __out PPORT_CONFIGURATION_INFORMATION pConfigInfo,
                __out      PBOOLEAN                        pBAgain
)
{
    ULONG              i,
                       len,
                       status = SP_RETURN_FOUND;
    PCHAR              pChar;
    pHW_HBA_EXT        pHBAExt = (pHW_HBA_EXT)DeviceExtension;
    NTSTATUS           ntstatus;
    
#if defined(_AMD64_)

    KLOCK_QUEUE_HANDLE LockHandle;

#else

    KIRQL              SaveIrql;

#endif

    UNREFERENCED_PARAMETER(pReservedArg1);
    UNREFERENCED_PARAMETER(pReservedArg2);
#ifdef USE_STORPORT
    UNREFERENCED_PARAMETER(pReservedArg3);
#endif
    UNREFERENCED_PARAMETER(ArgumentString);

    KdPrint2(("PhDskMnt::MpHwFindAdapter:  Arg=%s%s%s, pHBAExt = 0x%p, pConfigInfo = 0x%p, IRQL=%i\n",
        ArgumentString != NULL ? "\"" : "(",
        ArgumentString != NULL ? ArgumentString : "null",
        ArgumentString != NULL ? "\"" : ")",
        pHBAExt,
        pConfigInfo,
        KeGetCurrentIrql()));

    if (pMPDrvInfoGlobal->GlobalsInitialized)
    {
        LARGE_INTEGER wait_time;

        DbgPrint("PhDskMnt::MpHwFindAdapter: Already initialized.\n");

        wait_time.QuadPart = -1000000;
        KeDelayExecutionThread(KernelMode, FALSE, &wait_time);
    }

    KeInitializeSpinLock(&pHBAExt->LUListLock);
    InitializeListHead(&pHBAExt->LUList);

    pHBAExt->HostTargetId = (UCHAR)pMPDrvInfoGlobal->MPRegInfo.InitiatorID;

#ifdef USE_STORPORT
    pConfigInfo->VirtualDevice                  = TRUE;                        // Inidicate no real hardware.
    pConfigInfo->SynchronizationModel           = StorSynchronizeFullDuplex;
#endif
    pConfigInfo->WmiDataProvider                = FALSE;                       // Indicate WMI provider.
    pConfigInfo->MaximumTransferLength          = SP_UNINITIALIZED_VALUE;      // Indicate unlimited.
    pConfigInfo->AlignmentMask                  = 0x3;                         // Indicate DWORD alignment.
    pConfigInfo->CachesData                     = FALSE;                       // Indicate miniport wants flush and shutdown notification.
    pConfigInfo->MaximumNumberOfTargets         = SCSI_MAXIMUM_TARGETS;        // Indicate maximum targets.
    pConfigInfo->NumberOfBuses                  =
        (UCHAR) pMPDrvInfoGlobal->MPRegInfo.NumberOfBuses;                     // Indicate number of busses.
    pConfigInfo->ScatterGather                  = TRUE;                        // Indicate scatter-gather (explicit setting needed for Win2003 at least).
    pConfigInfo->AutoRequestSense               = TRUE;
    pConfigInfo->TaggedQueuing                  = TRUE;
    pConfigInfo->MultipleRequestPerLu           = TRUE;

    // Save Vendor Id, Product Id, Revision in device extension.

    pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.VendorId.Buffer;
    len = min(8, (pMPDrvInfoGlobal->MPRegInfo.VendorId.Length/2));
    for ( i = 0; i < len; i++, pChar+=2)
      pHBAExt->VendorId[i] = *pChar;

    pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.ProductId.Buffer;
    len = min(16, (pMPDrvInfoGlobal->MPRegInfo.ProductId.Length/2));
    for ( i = 0; i < len; i++, pChar+=2)
      pHBAExt->ProductId[i] = *pChar;

    pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.ProductRevision.Buffer;
    len = min(4, (pMPDrvInfoGlobal->MPRegInfo.ProductRevision.Length/2));
    for ( i = 0; i < len; i++, pChar+=2)
      pHBAExt->ProductRevision[i] = *pChar;

    // Add HBA extension to master driver object's linked list.

#if defined(_AMD64_)

    KeAcquireInStackQueuedSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &LockHandle);

#else

    KeAcquireSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &SaveIrql);

#endif

    InsertTailList(&pMPDrvInfoGlobal->ListMPHBAObj, &pHBAExt->List);

    pMPDrvInfoGlobal->DrvInfoNbrMPHBAObj++;

#if defined(_AMD64_)

    KeReleaseInStackQueuedSpinLock(&LockHandle);

#else

    KeReleaseSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, SaveIrql);

#endif

    if (!pMPDrvInfoGlobal->GlobalsInitialized)
    {
        HANDLE thread_handle;
        OBJECT_ATTRIBUTES object_attributes;

        KeInitializeSpinLock(&pMPDrvInfoGlobal->RequestListLock);
        InitializeListHead(&pMPDrvInfoGlobal->RequestList);
        KeInitializeEvent(&pMPDrvInfoGlobal->RequestEvent, SynchronizationEvent, FALSE);

#ifdef USE_SCSIPORT
        KeInitializeSpinLock(&pMPDrvInfoGlobal->ResponseListLock);
        KeInitializeEvent(&pMPDrvInfoGlobal->ResponseEvent, SynchronizationEvent, FALSE);
        InitializeListHead(&pMPDrvInfoGlobal->ResponseList);
#endif

        KeInitializeEvent(&pMPDrvInfoGlobal->StopWorker, NotificationEvent, FALSE);

        pMPDrvInfoGlobal->GlobalsInitialized = TRUE;

        InitializeObjectAttributes(&object_attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

        ntstatus = PsCreateSystemThread(
            &thread_handle,
            (ACCESS_MASK) 0L,
            &object_attributes,
            NULL,
            NULL,
            ImScsiWorkerThread,
            NULL);

        if (!NT_SUCCESS(ntstatus))
        {
            DbgPrint("PhDskMnt::ScsiGetLUExtension: Cannot create worker thread. (%#x)\n", ntstatus);

            status = SP_RETURN_ERROR;
        }
        else
        {
            ObReferenceObjectByHandle(
                thread_handle,
                FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                *PsThreadType,
                KernelMode,
                (PVOID*)&pMPDrvInfoGlobal->WorkerThread,
                NULL
                );

            ZwClose(thread_handle);

            //for (i = 0; i < pHBAExt->NbrLUNsperHBA; i++)
            //    ImScsiCreateLU(pHBAExt, 0, (UCHAR)i, 0);
        }
    }

//Done:
    *pBAgain = FALSE;    
        
    KdPrint2(("PhDskMnt::MpHwFindAdapter: End, status = 0x%x\n", status));

    return status;
}                                                     // End MpHwFindAdapter().
コード例 #28
0
ファイル: inspect.c プロジェクト: kcrazy/winekit
void
TLInspectALEConnectClassify(
   IN const FWPS_INCOMING_VALUES0* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
   IN OUT void* layerData,
   IN const FWPS_FILTER0* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT0* classifyOut
   )
/* ++

   This is the classifyFn function for the ALE connect (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, we first check if it is triggered by an ealier
   FwpsCompleteOperation0 call by looking for an pended connect that has been
   inspected. If found, we remove it from the connect list and return the 
   inspection result; otherwise we can conclude that the re-auth is triggered 
   by policy change so we queue it 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* pendedConnect = NULL;
   TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;

   ADDRESS_FAMILY addressFamily;
   FWPS_PACKET_INJECTION_STATE packetState;
   BOOLEAN signalWorkerThread;

   UNREFERENCED_PARAMETER(flowContext);
   UNREFERENCED_PARAMETER(filter);

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

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

      if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
          (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
      {
         classifyOut->actionType = FWP_ACTION_PERMIT;
         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.
      //
      pendedConnect = AllocateAndInitializePendedPacket(
                           inFixedValues,
                           inMetaValues,
                           addressFamily,
                           layerData,
                           TL_INSPECT_CONNECT_PACKET,
                           FWP_DIRECTION_OUTBOUND
                           );

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

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

      //
      // Pend the ALE_AUTH_CONNECT classify.
      //
      status = FwpsPendOperation0(
                  inMetaValues->completionHandle,
                  &pendedConnect->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, &pendedConnect->listEntry);
      pendedConnect = NULL; // ownership transferred

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

      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }
   }
   else // re-auth @ ALE_AUTH_CONNECT
   {
      FWP_DIRECTION packetDirection;
      //
      // The classify is the re-authorization for an existing connection, it 
      // could have been triggered for one of the three cases --
      //
      //    1) The re-auth is triggered by a FwpsCompleteOperation0 call to
      //       complete a ALE_AUTH_CONNECT classify pended earlier. 
      //    2) The re-auth is triggered by an outbound packet sent immediately
      //       after a policy change at ALE_AUTH_CONNECT layer.
      //    3) The re-auth is triggered by an inbound packet received 
      //       immediately after a policy change at ALE_AUTH_CONNECT layer.
      //

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

      if (packetDirection == FWP_DIRECTION_OUTBOUND)
      {
         LIST_ENTRY* listEntry;
         BOOLEAN authComplete = FALSE;

         //
         // We first check whether this is a FwpsCompleteOperation0- triggered
         // reauth by looking for a pended connect that has the inspection
         // decision recorded. If found, we return that decision and remove
         // the pended connect from the list.
         //

         KeAcquireInStackQueuedSpinLock(
            &gConnListLock,
            &connListLockHandle
            );

         for (listEntry = gConnList.Flink;
              listEntry != &gConnList;
              listEntry = listEntry->Flink)
         {
            pendedConnect = CONTAINING_RECORD(
                              listEntry,
                              TL_INSPECT_PENDED_PACKET,
                              listEntry
                              );

            if (IsMatchingConnectPacket(
                     inFixedValues,
                     addressFamily,
                     packetDirection,
                     pendedConnect
                  ) && (pendedConnect->authConnectDecision != 0))
            {
               ASSERT((pendedConnect->authConnectDecision == FWP_ACTION_PERMIT) ||
                      (pendedConnect->authConnectDecision == FWP_ACTION_BLOCK));
               
               classifyOut->actionType = pendedConnect->authConnectDecision;

               RemoveEntryList(&pendedConnect->listEntry);
               
               if (!gDriverUnloading &&
                   (pendedConnect->netBufferList != NULL) &&
                   (pendedConnect->authConnectDecision == FWP_ACTION_PERMIT))
               {
                  //
                  // Now the outbound connection has been authorized. If the
                  // pended connect has a net buffer list in it, we need it
                  // morph it into a data packet and queue it to the packet
                  // queue for send injecition.
                  //
                  pendedConnect->type = TL_INSPECT_DATA_PACKET;

                  KeAcquireInStackQueuedSpinLock(
                     &gPacketQueueLock,
                     &packetQueueLockHandle
                     );

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

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

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

               authComplete = TRUE;
               break;
            }
         }

         KeReleaseInStackQueuedSpinLock(&connListLockHandle);

         if (authComplete)
         {
            goto Exit;
         }
      }

      //
      // If we reach here it means this is a policy change triggered re-auth
      // for an pre-existing connection. For such a packet (inbound or 
      // outbound) we queue it to the packet queue and inspect it just like
      // other regular data packets from TRANSPORT layers.
      //

      ASSERT(layerData != NULL);

      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->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
      }
      else
      {
         //
         // Driver is being unloaded, permit any connect classify.
         //
         signalWorkerThread = FALSE;

         classifyOut->actionType = FWP_ACTION_PERMIT;
      }

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

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

   }

Exit:

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

   return;
}
コード例 #29
0
ファイル: storport.c プロジェクト: Moteesh/reactos
static
NTSTATUS
NTAPI
PortAddDevice(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PDEVICE_OBJECT PhysicalDeviceObject)
{
    PDRIVER_OBJECT_EXTENSION DriverObjectExtension;
    PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
    WCHAR NameBuffer[80];
    UNICODE_STRING DeviceName;
    PDEVICE_OBJECT Fdo = NULL;
    KLOCK_QUEUE_HANDLE LockHandle;
    NTSTATUS Status;

    DPRINT1("PortAddDevice(%p %p)\n",
            DriverObject, PhysicalDeviceObject);

    ASSERT(DriverObject);
    ASSERT(PhysicalDeviceObject);

    swprintf(NameBuffer,
             L"\\Device\\RaidPort%lu",
             PortNumber);
    RtlInitUnicodeString(&DeviceName, NameBuffer);
    PortNumber++;

    DPRINT1("Creating device: %wZ\n", &DeviceName);

    /* Create the port device */
    Status = IoCreateDevice(DriverObject,
                            sizeof(FDO_DEVICE_EXTENSION),
                            &DeviceName,
                            FILE_DEVICE_CONTROLLER,
                            FILE_DEVICE_SECURE_OPEN,
                            FALSE,
                            &Fdo);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("IoCreateDevice() failed (Status 0x%08lx)\n", Status);
        return Status;
    }

    DPRINT1("Created device: %wZ (%p)\n", &DeviceName, Fdo);

    /* Initialize the device */
    Fdo->Flags |= DO_DIRECT_IO;
    Fdo->Flags |= DO_POWER_PAGABLE;

    /* Initialize the device extension */
    DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
    RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));

    DeviceExtension->ExtensionType = FdoExtension;

    DeviceExtension->Device = Fdo;
    DeviceExtension->PhysicalDevice = PhysicalDeviceObject;

    DeviceExtension->PnpState = dsStopped;

    /* Attach the FDO to the device stack */
    Status = IoAttachDeviceToDeviceStackSafe(Fdo,
                                             PhysicalDeviceObject,
                                             &DeviceExtension->LowerDevice);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("IoAttachDeviceToDeviceStackSafe() failed (Status 0x%08lx)\n", Status);
        IoDeleteDevice(Fdo);
        return Status;
    }

    /* Insert the FDO to the drivers FDO list */
    DriverObjectExtension = IoGetDriverObjectExtension(DriverObject,
                                                       (PVOID)DriverEntry);
    ASSERT(DriverObjectExtension->ExtensionType == DriverExtension);

    DeviceExtension->DriverExtension = DriverObjectExtension;

    KeAcquireInStackQueuedSpinLock(&DriverObjectExtension->AdapterListLock,
                                   &LockHandle);

    InsertHeadList(&DriverObjectExtension->AdapterListHead,
                   &DeviceExtension->AdapterListEntry);
    DriverObjectExtension->AdapterCount++;

    KeReleaseInStackQueuedSpinLock(&LockHandle);

    /* The device has been initialized */
    Fdo->Flags &= ~DO_DEVICE_INITIALIZING;

    DPRINT1("PortAddDevice() done (Status 0x%08lx)\n", Status);

    return Status;
}
コード例 #30
0
ファイル: inspect.c プロジェクト: kcrazy/winekit
void
TLInspectALERecvAcceptClassify(
   IN const FWPS_INCOMING_VALUES0* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
   IN OUT void* layerData,
   IN const FWPS_FILTER0* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT0* classifyOut
   )
/* ++

   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;

   UNREFERENCED_PARAMETER(flowContext);
   UNREFERENCED_PARAMETER(filter);


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

  ASSERT(layerData != NULL);

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

   if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
       (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
   {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      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;
      }

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

      //
      // Pend the ALE_AUTH_RECV_ACCEPT classify.
      //
      status = FwpsPendOperation0(
                  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->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.
      //

      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->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
      }
      else
      {
         //
         // Driver is being unloaded, permit any connect classify.
         //
         signalWorkerThread = FALSE;

         classifyOut->actionType = FWP_ACTION_PERMIT;
      }

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

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

Exit:

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

   return;
}