Revise adapter pausing
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
2ee3a99690
commit
b157105c58
59
wintun.c
59
wintun.c
@ -167,12 +167,18 @@ static NTSTATUS TunCheckForPause(_Inout_ TUN_CTX *ctx, _In_ LONG64 increment)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
static void TunCompletePause(_Inout_ TUN_CTX *ctx, _In_ LONG64 decrement)
|
static NDIS_STATUS TunCompletePause(_Inout_ TUN_CTX *ctx, _In_ LONG64 decrement)
|
||||||
{
|
{
|
||||||
ASSERT(decrement <= InterlockedGet64(&ctx->ActiveTransactionCount));
|
ASSERT(decrement <= InterlockedGet64(&ctx->ActiveTransactionCount));
|
||||||
if (!InterlockedSubtract64(&ctx->ActiveTransactionCount, decrement) &&
|
if (!InterlockedSubtract64(&ctx->ActiveTransactionCount, decrement) &&
|
||||||
InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_PAUSED, TUN_STATE_PAUSING) == TUN_STATE_PAUSING)
|
InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_PAUSED, TUN_STATE_PAUSING) == TUN_STATE_PAUSING) {
|
||||||
|
InterlockedExchange64(&ctx->Device.RefCount, 0);
|
||||||
|
TunIndicateStatus(ctx);
|
||||||
NdisMPauseComplete(ctx->MiniportAdapterHandle);
|
NdisMPauseComplete(ctx->MiniportAdapterHandle);
|
||||||
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NDIS_STATUS_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IO_CSQ_INSERT_IRP_EX TunCsqInsertIrpEx;
|
static IO_CSQ_INSERT_IRP_EX TunCsqInsertIrpEx;
|
||||||
@ -559,7 +565,7 @@ static NTSTATUS TunDispatchRead(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
|||||||
InterlockedIncrement64(&ctx->ActiveTransactionCount);
|
InterlockedIncrement64(&ctx->ActiveTransactionCount);
|
||||||
status = IoCsqInsertIrpEx(&ctx->Device.ReadQueue.Csq, Irp, NULL, TUN_CSQ_INSERT_TAIL);
|
status = IoCsqInsertIrpEx(&ctx->Device.ReadQueue.Csq, Irp, NULL, TUN_CSQ_INSERT_TAIL);
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
TunCompletePause(ctx, 1);
|
InterlockedDecrement64(&ctx->ActiveTransactionCount);
|
||||||
goto cleanup_TunCompletePause;
|
goto cleanup_TunCompletePause;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,8 +724,8 @@ static NTSTATUS TunDispatchCleanup(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
|||||||
goto cleanup_complete_req;
|
goto cleanup_complete_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG64 count = 0;
|
LONG64 count = 1;
|
||||||
if (!NT_SUCCESS(status = TunCheckForPause(ctx, 1)))
|
if (!NT_SUCCESS(status = TunCheckForPause(ctx, count)))
|
||||||
goto cleanup_TunCompletePause;
|
goto cleanup_TunCompletePause;
|
||||||
|
|
||||||
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(Irp);
|
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
@ -730,7 +736,7 @@ static NTSTATUS TunDispatchCleanup(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup_TunCompletePause:
|
cleanup_TunCompletePause:
|
||||||
TunCompletePause(ctx, 1LL + count);
|
TunCompletePause(ctx, count);
|
||||||
cleanup_complete_req:
|
cleanup_complete_req:
|
||||||
TunCompleteRequest(Irp, 0, status);
|
TunCompleteRequest(Irp, 0, status);
|
||||||
return status;
|
return status;
|
||||||
@ -749,16 +755,14 @@ _Use_decl_annotations_
|
|||||||
static NDIS_STATUS TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
|
static NDIS_STATUS TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
|
||||||
{
|
{
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
if (InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_PAUSING, TUN_STATE_RUNNING) != TUN_STATE_RUNNING)
|
|
||||||
return NDIS_STATUS_FAILURE;
|
|
||||||
|
|
||||||
/* Reset adapter context in device object, as Windows keeps calling dispatch handlers even after NdisDeregisterDeviceEx(). */
|
|
||||||
TUN_CTX **control_device_extension = (TUN_CTX **)NdisGetDeviceReservedExtension(ctx->Device.Object);
|
|
||||||
if (control_device_extension)
|
|
||||||
InterlockedExchangePointer(control_device_extension, NULL);
|
|
||||||
|
|
||||||
LONG64 count = 1;
|
LONG64 count = 1;
|
||||||
InterlockedAdd64(&ctx->ActiveTransactionCount, 1);
|
InterlockedAdd64(&ctx->ActiveTransactionCount, count);
|
||||||
|
|
||||||
|
if (InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_PAUSING, TUN_STATE_RUNNING) != TUN_STATE_RUNNING) {
|
||||||
|
InterlockedDecrement64(&ctx->ActiveTransactionCount);
|
||||||
|
return NDIS_STATUS_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
KLOCK_QUEUE_HANDLE lqh;
|
KLOCK_QUEUE_HANDLE lqh;
|
||||||
KeAcquireInStackQueuedSpinLock(&ctx->PacketQueue.Lock, &lqh);
|
KeAcquireInStackQueuedSpinLock(&ctx->PacketQueue.Lock, &lqh);
|
||||||
@ -780,14 +784,7 @@ static NDIS_STATUS TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_P
|
|||||||
TunCompleteRequest(pending_irp, 0, STATUS_CANCELLED);
|
TunCompleteRequest(pending_irp, 0, STATUS_CANCELLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
InterlockedExchange64(&ctx->Device.RefCount, 0); //TODO: Is this correct? Aren't handles still open potentially? Do we have to do something with the close handler?
|
return TunCompletePause(ctx, count);
|
||||||
TunIndicateStatus(ctx);
|
|
||||||
|
|
||||||
if (InterlockedSubtract64(&ctx->ActiveTransactionCount, count))
|
|
||||||
return NDIS_STATUS_PENDING;
|
|
||||||
|
|
||||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_PAUSED);
|
|
||||||
return NDIS_STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MINIPORT_RESTART TunRestart;
|
static MINIPORT_RESTART TunRestart;
|
||||||
@ -798,10 +795,6 @@ static NDIS_STATUS TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT
|
|||||||
if (InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_RESTARTING, TUN_STATE_PAUSED) != TUN_STATE_PAUSED)
|
if (InterlockedCompareExchange((LONG *)&ctx->State, TUN_STATE_RESTARTING, TUN_STATE_PAUSED) != TUN_STATE_PAUSED)
|
||||||
return NDIS_STATUS_FAILURE;
|
return NDIS_STATUS_FAILURE;
|
||||||
|
|
||||||
TUN_CTX **control_device_extension = (TUN_CTX **)NdisGetDeviceReservedExtension(ctx->Device.Object);
|
|
||||||
if (control_device_extension)
|
|
||||||
InterlockedExchangePointer(control_device_extension, ctx);
|
|
||||||
|
|
||||||
ASSERT(!InterlockedGet64(&ctx->Device.RefCount));
|
ASSERT(!InterlockedGet64(&ctx->Device.RefCount));
|
||||||
TunIndicateStatus(ctx);
|
TunIndicateStatus(ctx);
|
||||||
|
|
||||||
@ -1089,9 +1082,18 @@ static NDIS_STATUS TunInitializeEx(NDIS_HANDLE MiniportAdapterHandle, NDIS_HANDL
|
|||||||
ctx->Device.Object->Flags &= ~DO_BUFFERED_IO;
|
ctx->Device.Object->Flags &= ~DO_BUFFERED_IO;
|
||||||
ctx->Device.Object->Flags |= DO_DIRECT_IO;
|
ctx->Device.Object->Flags |= DO_DIRECT_IO;
|
||||||
|
|
||||||
|
TUN_CTX **control_device_extension = (TUN_CTX **)NdisGetDeviceReservedExtension(ctx->Device.Object);
|
||||||
|
if (!control_device_extension) {
|
||||||
|
status = NDIS_STATUS_FAILURE;
|
||||||
|
goto cleanup_NdisDeregisterDeviceEx;
|
||||||
|
}
|
||||||
|
InterlockedExchangePointer(control_device_extension, ctx);
|
||||||
|
|
||||||
ctx->State = TUN_STATE_PAUSED;
|
ctx->State = TUN_STATE_PAUSED;
|
||||||
return NDIS_STATUS_SUCCESS;
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
cleanup_NdisDeregisterDeviceEx:
|
||||||
|
NdisDeregisterDeviceEx(ctx->Device.Handle);
|
||||||
cleanup_NdisFreeNetBufferListPool:
|
cleanup_NdisFreeNetBufferListPool:
|
||||||
NdisFreeNetBufferListPool(ctx->NBLPool);
|
NdisFreeNetBufferListPool(ctx->NBLPool);
|
||||||
cleanup_ctx:
|
cleanup_ctx:
|
||||||
@ -1117,6 +1119,11 @@ static void TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltA
|
|||||||
ASSERT(!InterlockedGet64(&ctx->ActiveTransactionCount));
|
ASSERT(!InterlockedGet64(&ctx->ActiveTransactionCount));
|
||||||
ASSERT(!InterlockedGet64(&ctx->Device.RefCount));
|
ASSERT(!InterlockedGet64(&ctx->Device.RefCount));
|
||||||
|
|
||||||
|
/* Reset adapter context in device object, as Windows keeps calling dispatch handlers even after NdisDeregisterDeviceEx(). */
|
||||||
|
TUN_CTX **control_device_extension = (TUN_CTX **)NdisGetDeviceReservedExtension(ctx->Device.Object);
|
||||||
|
if (control_device_extension)
|
||||||
|
InterlockedExchangePointer(control_device_extension, NULL);
|
||||||
|
|
||||||
/* Release resources. */
|
/* Release resources. */
|
||||||
NdisDeregisterDeviceEx(ctx->Device.Handle);
|
NdisDeregisterDeviceEx(ctx->Device.Handle);
|
||||||
NdisFreeNetBufferListPool(ctx->NBLPool);
|
NdisFreeNetBufferListPool(ctx->NBLPool);
|
||||||
|
Loading…
Reference in New Issue
Block a user