Reorder source code
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
bbbe72ce84
commit
ced1bcdd52
432
wintun.c
432
wintun.c
@ -35,6 +35,18 @@
|
|||||||
#define TUN_EXCH_MIN_BUFFER_SIZE_WRITE (sizeof(TUN_PACKET)) // Minimum size of write exchange buffer
|
#define TUN_EXCH_MIN_BUFFER_SIZE_WRITE (sizeof(TUN_PACKET)) // Minimum size of write exchange buffer
|
||||||
#define TUN_QUEUE_MAX_NBLS 1000
|
#define TUN_QUEUE_MAX_NBLS 1000
|
||||||
#define TUN_MEMORY_TAG 'wtun'
|
#define TUN_MEMORY_TAG 'wtun'
|
||||||
|
#define TUN_CSQ_INSERT_HEAD ((PVOID)TRUE)
|
||||||
|
#define TUN_CSQ_INSERT_TAIL ((PVOID)FALSE)
|
||||||
|
|
||||||
|
#if REG_DWORD == REG_DWORD_BIG_ENDIAN
|
||||||
|
#define TUN_HTONS(x) ((USHORT)(x))
|
||||||
|
#define TUN_HTONL(x) ((ULONG)(x))
|
||||||
|
#elif REG_DWORD == REG_DWORD_LITTLE_ENDIAN
|
||||||
|
#define TUN_HTONS(x) (((USHORT)(x) & 0x00ff) << 8 | ((USHORT)(x) & 0xff00) >> 8)
|
||||||
|
#define TUN_HTONL(x) (((ULONG)(x) & 0x000000ff) << 24 | ((ULONG)(x) & 0x0000ff00) << 8 | ((ULONG)(x) & 0x00ff0000) >> 8 | ((ULONG)(x) & 0xff000000) >> 24)
|
||||||
|
#else
|
||||||
|
#error "Unable to determine endianess"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _TUN_PACKET {
|
typedef struct _TUN_PACKET {
|
||||||
ULONG Size; // Size of packet data (TUN_EXCH_MAX_IP_PACKET_SIZE max)
|
ULONG Size; // Size of packet data (TUN_EXCH_MAX_IP_PACKET_SIZE max)
|
||||||
@ -104,19 +116,6 @@ static PVOID TunNotifyInterfaceChangeHandle;
|
|||||||
static NDIS_HANDLE NdisMiniportDriverHandle;
|
static NDIS_HANDLE NdisMiniportDriverHandle;
|
||||||
static volatile LONG64 AdapterCount;
|
static volatile LONG64 AdapterCount;
|
||||||
|
|
||||||
#if REG_DWORD == REG_DWORD_BIG_ENDIAN
|
|
||||||
#define TUN_HTONS(x) ((USHORT)(x))
|
|
||||||
#define TUN_HTONL(x) ((ULONG)(x))
|
|
||||||
#elif REG_DWORD == REG_DWORD_LITTLE_ENDIAN
|
|
||||||
#define TUN_HTONS(x) (((USHORT)(x) & 0x00ff) << 8 | ((USHORT)(x) & 0xff00) >> 8)
|
|
||||||
#define TUN_HTONL(x) (((ULONG)(x) & 0x000000ff) << 24 | ((ULONG)(x) & 0x0000ff00) << 8 | ((ULONG)(x) & 0x00ff0000) >> 8 | ((ULONG)(x) & 0xff000000) >> 24)
|
|
||||||
#else
|
|
||||||
#error "Unable to determine endianess"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TUN_CSQ_INSERT_HEAD ((PVOID)TRUE)
|
|
||||||
#define TUN_CSQ_INSERT_TAIL ((PVOID)FALSE)
|
|
||||||
|
|
||||||
#define InterlockedGet(val) (InterlockedAdd((val), 0))
|
#define InterlockedGet(val) (InterlockedAdd((val), 0))
|
||||||
#define InterlockedGet64(val) (InterlockedAdd64((val), 0))
|
#define InterlockedGet64(val) (InterlockedAdd64((val), 0))
|
||||||
#define InterlockedGetPointer(val) (InterlockedCompareExchangePointer((val), NULL, NULL))
|
#define InterlockedGetPointer(val) (InterlockedCompareExchangePointer((val), NULL, NULL))
|
||||||
@ -259,13 +258,6 @@ static VOID TunCsqCompleteCanceledIrp(IO_CSQ *Csq, IRP *Irp)
|
|||||||
TunCompleteRequest(ctx, Irp, STATUS_CANCELLED, IO_NO_INCREMENT);
|
TunCompleteRequest(ctx, Irp, STATUS_CANCELLED, IO_NO_INCREMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_same_
|
|
||||||
static void TunSetNBLStatus(_Inout_opt_ NET_BUFFER_LIST *nbl, _In_ NDIS_STATUS status)
|
|
||||||
{
|
|
||||||
for (; nbl; nbl = NET_BUFFER_LIST_NEXT_NBL(nbl))
|
|
||||||
NET_BUFFER_LIST_STATUS(nbl) = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
_Must_inspect_result_
|
_Must_inspect_result_
|
||||||
static NTSTATUS TunGetIrpBuffer(_In_ IRP *Irp, _Out_ UCHAR **buffer, _Out_ ULONG *size)
|
static NTSTATUS TunGetIrpBuffer(_In_ IRP *Irp, _Out_ UCHAR **buffer, _Out_ ULONG *size)
|
||||||
@ -588,6 +580,63 @@ static void TunQueueProcess(_Inout_ TUN_CTX *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_same_
|
||||||
|
static void TunSetNBLStatus(_Inout_opt_ NET_BUFFER_LIST *nbl, _In_ NDIS_STATUS status)
|
||||||
|
{
|
||||||
|
for (; nbl; nbl = NET_BUFFER_LIST_NEXT_NBL(nbl))
|
||||||
|
NET_BUFFER_LIST_STATUS(nbl) = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MINIPORT_SEND_NET_BUFFER_LISTS TunSendNetBufferLists;
|
||||||
|
_Use_decl_annotations_
|
||||||
|
static void TunSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext, NET_BUFFER_LIST *NetBufferLists, NDIS_PORT_NUMBER PortNumber, ULONG SendFlags)
|
||||||
|
{
|
||||||
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
|
|
||||||
|
KIRQL irql = ExAcquireSpinLockShared(&ctx->TransitionLock);
|
||||||
|
|
||||||
|
NDIS_STATUS status;
|
||||||
|
if (!NT_SUCCESS(status = TunCheckForPause(ctx))) {
|
||||||
|
TunSetNBLStatus(NetBufferLists, status);
|
||||||
|
NdisMSendNetBufferListsComplete(ctx->MiniportAdapterHandle, NetBufferLists, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
|
||||||
|
goto cleanup_TunCompletePause;
|
||||||
|
}
|
||||||
|
|
||||||
|
TunQueueAppend(ctx, NetBufferLists, TUN_QUEUE_MAX_NBLS);
|
||||||
|
|
||||||
|
TunQueueProcess(ctx);
|
||||||
|
|
||||||
|
cleanup_TunCompletePause:
|
||||||
|
TunCompletePause(ctx, TRUE);
|
||||||
|
ExReleaseSpinLockShared(&ctx->TransitionLock, irql);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MINIPORT_CANCEL_SEND TunCancelSend;
|
||||||
|
_Use_decl_annotations_
|
||||||
|
static void TunCancelSend(NDIS_HANDLE MiniportAdapterContext, PVOID CancelId)
|
||||||
|
{
|
||||||
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
|
KLOCK_QUEUE_HANDLE lqh;
|
||||||
|
|
||||||
|
KeAcquireInStackQueuedSpinLock(&ctx->PacketQueue.Lock, &lqh);
|
||||||
|
|
||||||
|
NET_BUFFER_LIST *nbl_last = NULL, **nbl_last_link = &ctx->PacketQueue.FirstNbl;
|
||||||
|
for (NET_BUFFER_LIST *nbl = ctx->PacketQueue.FirstNbl, *nbl_next; nbl; nbl = nbl_next) {
|
||||||
|
nbl_next = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
||||||
|
if (NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(nbl) == CancelId) {
|
||||||
|
NET_BUFFER_LIST_STATUS(nbl) = NDIS_STATUS_SEND_ABORTED;
|
||||||
|
*nbl_last_link = nbl_next;
|
||||||
|
TunNBLRefDec(ctx, nbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
|
||||||
|
} else {
|
||||||
|
nbl_last = nbl;
|
||||||
|
nbl_last_link = &NET_BUFFER_LIST_NEXT_NBL(nbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->PacketQueue.LastNbl = nbl_last;
|
||||||
|
|
||||||
|
KeReleaseInStackQueuedSpinLock(&lqh);
|
||||||
|
}
|
||||||
|
|
||||||
#define IRP_REFCOUNT(irp) ((volatile LONG *)&(irp)->Tail.Overlay.DriverContext[0])
|
#define IRP_REFCOUNT(irp) ((volatile LONG *)&(irp)->Tail.Overlay.DriverContext[0])
|
||||||
#define NET_BUFFER_LIST_IRP(nbl) (NET_BUFFER_LIST_MINIPORT_RESERVED(nbl)[0])
|
#define NET_BUFFER_LIST_IRP(nbl) (NET_BUFFER_LIST_MINIPORT_RESERVED(nbl)[0])
|
||||||
|
|
||||||
@ -716,46 +765,40 @@ cleanup_TunCompletePause:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
static MINIPORT_RETURN_NET_BUFFER_LISTS TunReturnNetBufferLists;
|
||||||
static void TunForceHandlesClosed(_Inout_ TUN_CTX *ctx)
|
_Use_decl_annotations_
|
||||||
|
static void TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST NetBufferLists, ULONG ReturnFlags)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
PEPROCESS process;
|
|
||||||
KAPC_STATE apc_state;
|
|
||||||
PVOID object;
|
|
||||||
OBJECT_HANDLE_INFORMATION handle_info;
|
|
||||||
SYSTEM_HANDLE_INFORMATION_EX *table = NULL;
|
|
||||||
|
|
||||||
for (ULONG size = 0, req; (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, table, size, &req)) == STATUS_INFO_LENGTH_MISMATCH; size = req) {
|
LONG64 stat_size = 0, stat_p_ok = 0, stat_p_err = 0;
|
||||||
if (table)
|
for (NET_BUFFER_LIST *nbl = NetBufferLists, *nbl_next; nbl; nbl = nbl_next) {
|
||||||
ExFreePoolWithTag(table, TUN_HTONL(TUN_MEMORY_TAG));
|
nbl_next = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
||||||
table = ExAllocatePoolWithTag(PagedPool, req, TUN_HTONL(TUN_MEMORY_TAG));
|
NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;
|
||||||
if (!table)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!NT_SUCCESS(status) || !table)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (ULONG_PTR i = 0; i < table->NumberOfHandles; ++i) {
|
IRP *irp = NET_BUFFER_LIST_IRP(nbl);
|
||||||
FILE_OBJECT *file = table->Handles[i].Object; //XXX: We should probably first look at table->Handles[i].ObjectTypeIndex, but the value changes lots between NT versions.
|
MDL *mdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(nbl));
|
||||||
if (!file || file->Type != 5 || file->DeviceObject != ctx->Device.Object)
|
if (NT_SUCCESS(NET_BUFFER_LIST_STATUS(nbl))) {
|
||||||
continue;
|
ULONG p_size = MmGetMdlByteCount(mdl);
|
||||||
status = PsLookupProcessByProcessId(table->Handles[i].UniqueProcessId, &process);
|
stat_size += p_size;
|
||||||
if (!NT_SUCCESS(status))
|
stat_p_ok++;
|
||||||
continue;
|
} else
|
||||||
KeStackAttachProcess(process, &apc_state);
|
stat_p_err++;
|
||||||
status = ObReferenceObjectByHandle(table->Handles[i].HandleValue, 0, NULL, UserMode, &object, &handle_info);
|
|
||||||
if (NT_SUCCESS(status)) {
|
NdisFreeMdl(mdl);
|
||||||
if (object == file)
|
NdisFreeNetBufferList(nbl);
|
||||||
ObCloseHandle(table->Handles[i].HandleValue, UserMode);
|
|
||||||
ObfDereferenceObject(object);
|
ASSERT(InterlockedGet(IRP_REFCOUNT(irp)) > 0);
|
||||||
|
if (InterlockedDecrement(IRP_REFCOUNT(irp)) <= 0) {
|
||||||
|
TunCompleteRequest(ctx, irp, STATUS_SUCCESS, IO_NETWORK_INCREMENT);
|
||||||
|
TunCompletePause(ctx, TRUE);
|
||||||
}
|
}
|
||||||
KeUnstackDetachProcess(&apc_state);
|
|
||||||
ObfDereferenceObject(process);
|
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
if (table)
|
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInOctets, stat_size);
|
||||||
ExFreePoolWithTag(table, TUN_HTONL(TUN_MEMORY_TAG));
|
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInUcastOctets, stat_size);
|
||||||
|
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInUcastPkts, stat_p_ok);
|
||||||
|
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifInErrors, stat_p_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DRIVER_DISPATCH TunDispatch;
|
static DRIVER_DISPATCH TunDispatch;
|
||||||
@ -845,6 +888,19 @@ cleanup_complete_req:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MINIPORT_RESTART TunRestart;
|
||||||
|
_Use_decl_annotations_
|
||||||
|
static NDIS_STATUS TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
|
||||||
|
{
|
||||||
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
|
|
||||||
|
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RESTARTING);
|
||||||
|
InterlockedExchange64(&ctx->ActiveTransactionCount, 1);
|
||||||
|
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RUNNING);
|
||||||
|
|
||||||
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static MINIPORT_PAUSE TunPause;
|
static MINIPORT_PAUSE TunPause;
|
||||||
_Use_decl_annotations_
|
_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)
|
||||||
@ -859,111 +915,12 @@ static NDIS_STATUS TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_P
|
|||||||
return TunCompletePause(ctx, FALSE);
|
return TunCompletePause(ctx, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MINIPORT_RESTART TunRestart;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static NDIS_STATUS TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
|
|
||||||
{
|
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
||||||
|
|
||||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RESTARTING);
|
|
||||||
InterlockedExchange64(&ctx->ActiveTransactionCount, 1);
|
|
||||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RUNNING);
|
|
||||||
|
|
||||||
return NDIS_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MINIPORT_RETURN_NET_BUFFER_LISTS TunReturnNetBufferLists;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static void TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST NetBufferLists, ULONG ReturnFlags)
|
|
||||||
{
|
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
||||||
|
|
||||||
LONG64 stat_size = 0, stat_p_ok = 0, stat_p_err = 0;
|
|
||||||
for (NET_BUFFER_LIST *nbl = NetBufferLists, *nbl_next; nbl; nbl = nbl_next) {
|
|
||||||
nbl_next = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
||||||
NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;
|
|
||||||
|
|
||||||
IRP *irp = NET_BUFFER_LIST_IRP(nbl);
|
|
||||||
MDL *mdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(nbl));
|
|
||||||
if (NT_SUCCESS(NET_BUFFER_LIST_STATUS(nbl))) {
|
|
||||||
ULONG p_size = MmGetMdlByteCount(mdl);
|
|
||||||
stat_size += p_size;
|
|
||||||
stat_p_ok++;
|
|
||||||
} else
|
|
||||||
stat_p_err++;
|
|
||||||
|
|
||||||
NdisFreeMdl(mdl);
|
|
||||||
NdisFreeNetBufferList(nbl);
|
|
||||||
|
|
||||||
ASSERT(InterlockedGet(IRP_REFCOUNT(irp)) > 0);
|
|
||||||
if (InterlockedDecrement(IRP_REFCOUNT(irp)) <= 0) {
|
|
||||||
TunCompleteRequest(ctx, irp, STATUS_SUCCESS, IO_NETWORK_INCREMENT);
|
|
||||||
TunCompletePause(ctx, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInOctets, stat_size);
|
|
||||||
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInUcastOctets, stat_size);
|
|
||||||
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifHCInUcastPkts, stat_p_ok);
|
|
||||||
InterlockedAdd64((LONG64 *)&ctx->Statistics.ifInErrors, stat_p_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MINIPORT_CANCEL_SEND TunCancelSend;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static void TunCancelSend(NDIS_HANDLE MiniportAdapterContext, PVOID CancelId)
|
|
||||||
{
|
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
||||||
KLOCK_QUEUE_HANDLE lqh;
|
|
||||||
|
|
||||||
KeAcquireInStackQueuedSpinLock(&ctx->PacketQueue.Lock, &lqh);
|
|
||||||
|
|
||||||
NET_BUFFER_LIST *nbl_last = NULL, **nbl_last_link = &ctx->PacketQueue.FirstNbl;
|
|
||||||
for (NET_BUFFER_LIST *nbl = ctx->PacketQueue.FirstNbl, *nbl_next; nbl; nbl = nbl_next) {
|
|
||||||
nbl_next = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
||||||
if (NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(nbl) == CancelId) {
|
|
||||||
NET_BUFFER_LIST_STATUS(nbl) = NDIS_STATUS_SEND_ABORTED;
|
|
||||||
*nbl_last_link = nbl_next;
|
|
||||||
TunNBLRefDec(ctx, nbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
|
|
||||||
} else {
|
|
||||||
nbl_last = nbl;
|
|
||||||
nbl_last_link = &NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->PacketQueue.LastNbl = nbl_last;
|
|
||||||
|
|
||||||
KeReleaseInStackQueuedSpinLock(&lqh);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MINIPORT_DEVICE_PNP_EVENT_NOTIFY TunDevicePnPEventNotify;
|
static MINIPORT_DEVICE_PNP_EVENT_NOTIFY TunDevicePnPEventNotify;
|
||||||
_Use_decl_annotations_
|
_Use_decl_annotations_
|
||||||
static void TunDevicePnPEventNotify(NDIS_HANDLE MiniportAdapterContext, PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
|
static void TunDevicePnPEventNotify(NDIS_HANDLE MiniportAdapterContext, PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static MINIPORT_SHUTDOWN TunShutdownEx;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static void TunShutdownEx(NDIS_HANDLE MiniportAdapterContext, NDIS_SHUTDOWN_ACTION ShutdownAction)
|
|
||||||
{
|
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
||||||
|
|
||||||
if (ShutdownAction == NdisShutdownBugCheck)
|
|
||||||
return;
|
|
||||||
|
|
||||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_SHUTDOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MINIPORT_CANCEL_DIRECT_OID_REQUEST TunCancelDirectOidRequest;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static void TunCancelDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static MINIPORT_CANCEL_OID_REQUEST TunCancelOidRequest;
|
|
||||||
_Use_decl_annotations_
|
|
||||||
static void TunCancelOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_NOTIFICATION_CALLBACK_ROUTINE TunPnPNotifyDeviceChange;
|
static DRIVER_NOTIFICATION_CALLBACK_ROUTINE TunPnPNotifyDeviceChange;
|
||||||
_Use_decl_annotations_
|
_Use_decl_annotations_
|
||||||
static NTSTATUS TunPnPNotifyDeviceChange(PVOID NotificationStruct, PVOID Context)
|
static NTSTATUS TunPnPNotifyDeviceChange(PVOID NotificationStruct, PVOID Context)
|
||||||
@ -1283,12 +1240,46 @@ cleanup_NdisDeregisterDeviceEx:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MINIPORT_UNLOAD TunUnload;
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||||
_Use_decl_annotations_
|
static void TunForceHandlesClosed(_Inout_ TUN_CTX *ctx)
|
||||||
static VOID TunUnload(PDRIVER_OBJECT DriverObject)
|
|
||||||
{
|
{
|
||||||
IoUnregisterPlugPlayNotificationEx(TunNotifyInterfaceChangeHandle);
|
NTSTATUS status;
|
||||||
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
|
PEPROCESS process;
|
||||||
|
KAPC_STATE apc_state;
|
||||||
|
PVOID object;
|
||||||
|
OBJECT_HANDLE_INFORMATION handle_info;
|
||||||
|
SYSTEM_HANDLE_INFORMATION_EX *table = NULL;
|
||||||
|
|
||||||
|
for (ULONG size = 0, req; (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, table, size, &req)) == STATUS_INFO_LENGTH_MISMATCH; size = req) {
|
||||||
|
if (table)
|
||||||
|
ExFreePoolWithTag(table, TUN_HTONL(TUN_MEMORY_TAG));
|
||||||
|
table = ExAllocatePoolWithTag(PagedPool, req, TUN_HTONL(TUN_MEMORY_TAG));
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!NT_SUCCESS(status) || !table)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for (ULONG_PTR i = 0; i < table->NumberOfHandles; ++i) {
|
||||||
|
FILE_OBJECT *file = table->Handles[i].Object; //XXX: We should probably first look at table->Handles[i].ObjectTypeIndex, but the value changes lots between NT versions.
|
||||||
|
if (!file || file->Type != 5 || file->DeviceObject != ctx->Device.Object)
|
||||||
|
continue;
|
||||||
|
status = PsLookupProcessByProcessId(table->Handles[i].UniqueProcessId, &process);
|
||||||
|
if (!NT_SUCCESS(status))
|
||||||
|
continue;
|
||||||
|
KeStackAttachProcess(process, &apc_state);
|
||||||
|
status = ObReferenceObjectByHandle(table->Handles[i].HandleValue, 0, NULL, UserMode, &object, &handle_info);
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
if (object == file)
|
||||||
|
ObCloseHandle(table->Handles[i].HandleValue, UserMode);
|
||||||
|
ObfDereferenceObject(object);
|
||||||
|
}
|
||||||
|
KeUnstackDetachProcess(&apc_state);
|
||||||
|
ObfDereferenceObject(process);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (table)
|
||||||
|
ExFreePoolWithTag(table, TUN_HTONL(TUN_MEMORY_TAG));
|
||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_max_(APC_LEVEL)
|
_IRQL_requires_max_(APC_LEVEL)
|
||||||
@ -1358,49 +1349,16 @@ static void TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltA
|
|||||||
NdisDeregisterDeviceEx(ctx->Device.Handle);
|
NdisDeregisterDeviceEx(ctx->Device.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
static MINIPORT_SHUTDOWN TunShutdownEx;
|
||||||
static NDIS_STATUS TunOidSet(_Inout_ TUN_CTX *ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
|
_Use_decl_annotations_
|
||||||
|
static void TunShutdownEx(NDIS_HANDLE MiniportAdapterContext, NDIS_SHUTDOWN_ACTION ShutdownAction)
|
||||||
{
|
{
|
||||||
ASSERT(OidRequest->RequestType == NdisRequestSetInformation);
|
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||||
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesNeeded =
|
if (ShutdownAction == NdisShutdownBugCheck)
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
return;
|
||||||
|
|
||||||
switch (OidRequest->DATA.SET_INFORMATION.Oid) {
|
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_SHUTDOWN);
|
||||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
||||||
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
||||||
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != 4) {
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
|
||||||
return NDIS_STATUS_INVALID_LENGTH;
|
|
||||||
}
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesRead = 4;
|
|
||||||
return NDIS_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
case OID_GEN_LINK_PARAMETERS:
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesRead = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
|
||||||
return NDIS_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
case OID_GEN_INTERRUPT_MODERATION:
|
|
||||||
return NDIS_STATUS_INVALID_DATA;
|
|
||||||
|
|
||||||
case OID_PNP_SET_POWER:
|
|
||||||
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE)) {
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
|
|
||||||
return NDIS_STATUS_INVALID_LENGTH;
|
|
||||||
}
|
|
||||||
OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
|
||||||
|
|
||||||
NDIS_DEVICE_POWER_STATE state = *(NDIS_DEVICE_POWER_STATE *)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
||||||
KIRQL irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
|
||||||
InterlockedExchange((LONG *)&ctx->PowerState, state);
|
|
||||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
|
||||||
if (state >= NdisDeviceStateD1)
|
|
||||||
TunQueueClear(ctx, STATUS_NDIS_LOW_POWER_STATE);
|
|
||||||
|
|
||||||
return NDIS_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NDIS_STATUS_NOT_SUPPORTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_IRQL_requires_max_(APC_LEVEL)
|
_IRQL_requires_max_(APC_LEVEL)
|
||||||
@ -1522,6 +1480,50 @@ static NDIS_STATUS TunOidQuery(_Inout_ TUN_CTX *ctx, _Inout_ NDIS_OID_REQUEST *O
|
|||||||
return NDIS_STATUS_NOT_SUPPORTED;
|
return NDIS_STATUS_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||||
|
static NDIS_STATUS TunOidSet(_Inout_ TUN_CTX *ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
|
||||||
|
{
|
||||||
|
ASSERT(OidRequest->RequestType == NdisRequestSetInformation);
|
||||||
|
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = OidRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
||||||
|
|
||||||
|
switch (OidRequest->DATA.SET_INFORMATION.Oid) {
|
||||||
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||||
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
||||||
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != 4) {
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
||||||
|
return NDIS_STATUS_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesRead = 4;
|
||||||
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
case OID_GEN_LINK_PARAMETERS:
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesRead = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
||||||
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
case OID_GEN_INTERRUPT_MODERATION:
|
||||||
|
return NDIS_STATUS_INVALID_DATA;
|
||||||
|
|
||||||
|
case OID_PNP_SET_POWER:
|
||||||
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE)) {
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
|
||||||
|
return NDIS_STATUS_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
||||||
|
|
||||||
|
NDIS_DEVICE_POWER_STATE state = *(NDIS_DEVICE_POWER_STATE *)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
|
||||||
|
KIRQL irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||||
|
InterlockedExchange((LONG *)&ctx->PowerState, state);
|
||||||
|
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||||
|
if (state >= NdisDeviceStateD1)
|
||||||
|
TunQueueClear(ctx, STATUS_NDIS_LOW_POWER_STATE);
|
||||||
|
|
||||||
|
return NDIS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NDIS_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
static MINIPORT_OID_REQUEST TunOidRequest;
|
static MINIPORT_OID_REQUEST TunOidRequest;
|
||||||
_Use_decl_annotations_
|
_Use_decl_annotations_
|
||||||
static NDIS_STATUS TunOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
static NDIS_STATUS TunOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
||||||
@ -1539,6 +1541,12 @@ static NDIS_STATUS TunOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MINIPORT_CANCEL_OID_REQUEST TunCancelOidRequest;
|
||||||
|
_Use_decl_annotations_
|
||||||
|
static void TunCancelOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static MINIPORT_DIRECT_OID_REQUEST TunDirectOidRequest;
|
static MINIPORT_DIRECT_OID_REQUEST TunDirectOidRequest;
|
||||||
_Use_decl_annotations_
|
_Use_decl_annotations_
|
||||||
static NDIS_STATUS TunDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
static NDIS_STATUS TunDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
||||||
@ -1554,28 +1562,18 @@ static NDIS_STATUS TunDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MINIPORT_SEND_NET_BUFFER_LISTS TunSendNetBufferLists;
|
static MINIPORT_CANCEL_DIRECT_OID_REQUEST TunCancelDirectOidRequest;
|
||||||
_Use_decl_annotations_
|
_Use_decl_annotations_
|
||||||
static void TunSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext, NET_BUFFER_LIST *NetBufferLists, NDIS_PORT_NUMBER PortNumber, ULONG SendFlags)
|
static void TunCancelDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
||||||
{
|
{
|
||||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
||||||
|
|
||||||
KIRQL irql = ExAcquireSpinLockShared(&ctx->TransitionLock);
|
|
||||||
|
|
||||||
NDIS_STATUS status;
|
|
||||||
if (!NT_SUCCESS(status = TunCheckForPause(ctx))) {
|
|
||||||
TunSetNBLStatus(NetBufferLists, status);
|
|
||||||
NdisMSendNetBufferListsComplete(ctx->MiniportAdapterHandle, NetBufferLists, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
|
|
||||||
goto cleanup_TunCompletePause;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TunQueueAppend(ctx, NetBufferLists, TUN_QUEUE_MAX_NBLS);
|
static MINIPORT_UNLOAD TunUnload;
|
||||||
|
_Use_decl_annotations_
|
||||||
TunQueueProcess(ctx);
|
static VOID TunUnload(PDRIVER_OBJECT DriverObject)
|
||||||
|
{
|
||||||
cleanup_TunCompletePause:
|
IoUnregisterPlugPlayNotificationEx(TunNotifyInterfaceChangeHandle);
|
||||||
TunCompletePause(ctx, TRUE);
|
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
|
||||||
ExReleaseSpinLockShared(&ctx->TransitionLock, irql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DRIVER_INITIALIZE DriverEntry;
|
DRIVER_INITIALIZE DriverEntry;
|
||||||
|
Loading…
Reference in New Issue
Block a user