diff options
Diffstat (limited to 'wintun.c')
-rw-r--r-- | wintun.c | 1466 |
1 files changed, 0 insertions, 1466 deletions
diff --git a/wintun.c b/wintun.c deleted file mode 100644 index 624de2f..0000000 --- a/wintun.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * - * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved. - */ - -#include <ntifs.h> -#include <wdm.h> -#include <wdmsec.h> -#include <ndis.h> -#include <ntstrsafe.h> -#include "undocumented.h" -#include "atomic.h" - -#pragma warning(disable : 4100) /* unreferenced formal parameter */ -#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */ -#pragma warning(disable : 4204) /* nonstandard: non-constant aggregate initializer */ -#pragma warning(disable : 4221) /* nonstandard: cannot be initialized using address of automatic variable */ -#pragma warning(disable : 6320) /* exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER */ - -#define NDIS_MINIPORT_VERSION_MIN ((NDIS_MINIPORT_MINIMUM_MAJOR_VERSION << 16) | NDIS_MINIPORT_MINIMUM_MINOR_VERSION) -#define NDIS_MINIPORT_VERSION_MAX ((NDIS_MINIPORT_MAJOR_VERSION << 16) | NDIS_MINIPORT_MINOR_VERSION) - -#define TUN_VENDOR_NAME "Wintun Tunnel" -#define TUN_VENDOR_ID 0xFFFFFF00 -#define TUN_LINK_SPEED 100000000000ULL /* 100gbps */ - -/* Memory alignment of packets and rings */ -#define TUN_ALIGNMENT sizeof(ULONG) -#define TUN_ALIGN(Size) (((ULONG)(Size) + ((ULONG)TUN_ALIGNMENT - 1)) & ~((ULONG)TUN_ALIGNMENT - 1)) -#define TUN_IS_ALIGNED(Size) (!((ULONG)(Size) & ((ULONG)TUN_ALIGNMENT - 1))) -/* Maximum IP packet size */ -#define TUN_MAX_IP_PACKET_SIZE 0xFFFF -/* Maximum packet size */ -#define TUN_MAX_PACKET_SIZE TUN_ALIGN(sizeof(TUN_PACKET) + TUN_MAX_IP_PACKET_SIZE) -/* Minimum ring capacity. */ -#define TUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */ -/* Maximum ring capacity. */ -#define TUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */ -/* Calculates ring capacity */ -#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT)) -/* Calculates ring offset modulo capacity */ -#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1)) - -#if REG_DWORD == REG_DWORD_BIG_ENDIAN -# define HTONS(x) ((USHORT)(x)) -# define HTONL(x) ((ULONG)(x)) -#elif REG_DWORD == REG_DWORD_LITTLE_ENDIAN -# define HTONS(x) ((((USHORT)(x)&0x00ff) << 8) | (((USHORT)(x)&0xff00) >> 8)) -# define 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_MEMORY_TAG HTONL('wtun') - -typedef struct _TUN_PACKET -{ - /* Size of packet data (TUN_MAX_IP_PACKET_SIZE max) */ - ULONG Size; - - /* Packet data */ - UCHAR _Field_size_bytes_(Size) - Data[]; -} TUN_PACKET; - -typedef struct _TUN_RING -{ - /* Byte offset of the first packet in the ring. Its value must be a multiple of TUN_ALIGNMENT and less than ring - * capacity. */ - volatile ULONG Head; - - /* Byte offset of the first free space in the ring. Its value must be multiple of TUN_ALIGNMENT and less than ring - * capacity. */ - volatile ULONG Tail; - - /* Non-zero when consumer is in alertable state. */ - volatile LONG Alertable; - - /* Ring data. Its capacity must be a power of 2 + extra TUN_MAX_PACKET_SIZE-TUN_ALIGNMENT space to - * eliminate need for wrapping. */ - UCHAR Data[]; -} TUN_RING; - -typedef struct _TUN_REGISTER_RINGS -{ - struct - { - /* Size of the ring */ - ULONG RingSize; - - /* Pointer to client allocated ring */ - TUN_RING *Ring; - - /* On send: An event created by the client the Wintun signals after it moves the Tail member of the send ring. - * On receive: An event created by the client the client will signal when it moves the Tail member of - * the receive ring if receive ring is alertable. */ - HANDLE TailMoved; - } Send, Receive; -} TUN_REGISTER_RINGS; - -/* Register rings hosted by the client. - * The lpInBuffer and nInBufferSize parameters of DeviceIoControl() must point to an TUN_REGISTER_RINGS struct. - * Client must wait for this IOCTL to finish before adding packets to the ring. */ -#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) -/* Force close all open handles to allow for updating. */ -#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) - -typedef struct _TUN_CTX -{ - volatile LONG Running; - - /* Used like RCU. When we're making use of rings, we take a shared lock. When we want to register or release the - * rings and toggle the state, we take an exclusive lock before toggling the atomic and then releasing. It's similar - * to setting the atomic and then calling rcu_barrier(). */ - EX_SPIN_LOCK TransitionLock; - - NDIS_HANDLE MiniportAdapterHandle; /* This is actually a pointer to NDIS_MINIPORT_BLOCK struct. */ - DEVICE_OBJECT *FunctionalDeviceObject; - NDIS_STATISTICS_INFO Statistics; - - struct - { - LIST_ENTRY Entry; - ERESOURCE RegistrationLock; - FILE_OBJECT *OwningFileObject; - HANDLE OwningProcessId; - KEVENT Disconnected; - - struct - { - MDL *Mdl; - TUN_RING *Ring; - ULONG Capacity; - KEVENT *TailMoved; - KSPIN_LOCK Lock; - ULONG RingTail; - struct - { - NET_BUFFER_LIST *Head, *Tail; - } ActiveNbls; - } Send; - - struct - { - MDL *Mdl; - TUN_RING *Ring; - ULONG Capacity; - KEVENT *TailMoved; - HANDLE Thread; - KSPIN_LOCK Lock; - struct - { - NET_BUFFER_LIST *Head, *Tail; - KEVENT Empty; - } ActiveNbls; - } Receive; - } Device; - - NDIS_HANDLE NblPool; -} TUN_CTX; - -static UINT NdisVersion; -static NDIS_HANDLE NdisMiniportDriverHandle; -static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose; -static ERESOURCE TunDispatchCtxGuard, TunDispatchDeviceListLock; -static RTL_STATIC_LIST_HEAD(TunDispatchDeviceList); -static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor; - -_IRQL_requires_max_(DISPATCH_LEVEL) -static VOID -TunIndicateStatus(_In_ NDIS_HANDLE MiniportAdapterHandle, _In_ NDIS_MEDIA_CONNECT_STATE MediaConnectState) -{ - NDIS_LINK_STATE State = { .Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT, - .Revision = NDIS_LINK_STATE_REVISION_1, - .Size = NDIS_SIZEOF_LINK_STATE_REVISION_1 }, - .MediaConnectState = MediaConnectState, - .MediaDuplexState = MediaDuplexStateFull, - .XmitLinkSpeed = TUN_LINK_SPEED, - .RcvLinkSpeed = TUN_LINK_SPEED, - .PauseFunctions = NdisPauseFunctionsUnsupported }; - - NDIS_STATUS_INDICATION Indication = { .Header = { .Type = NDIS_OBJECT_TYPE_STATUS_INDICATION, - .Revision = NDIS_STATUS_INDICATION_REVISION_1, - .Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1 }, - .SourceHandle = MiniportAdapterHandle, - .StatusCode = NDIS_STATUS_LINK_STATE, - .StatusBuffer = &State, - .StatusBufferSize = sizeof(State) }; - - NdisMIndicateStatusEx(MiniportAdapterHandle, &Indication); -} - -/* Send: We should not modify NET_BUFFER_LIST_NEXT_NBL(Nbl) to prevent fragmented NBLs to separate. - * Receive: NDIS may change NET_BUFFER_LIST_NEXT_NBL(Nbl) at will between the NdisMIndicateReceiveNetBufferLists() and - * MINIPORT_RETURN_NET_BUFFER_LISTS calls. Therefore, we use our own ->Next pointer for book-keeping. */ -#define NET_BUFFER_LIST_NEXT_NBL_EX(Nbl) (NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[1]) - -static VOID -TunNblSetOffsetAndMarkActive(_Inout_ NET_BUFFER_LIST *Nbl, _In_ ULONG Offset) -{ - ASSERT(TUN_IS_ALIGNED(Offset)); /* Alignment ensures bit 0 will be 0 (0=active, 1=completed). */ - NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[0] = (VOID *)Offset; -} - -static ULONG -TunNblGetOffset(_In_ NET_BUFFER_LIST *Nbl) -{ - return (ULONG)((ULONG_PTR)(NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[0]) & ~((ULONG_PTR)TUN_ALIGNMENT - 1)); -} - -static VOID -TunNblMarkCompleted(_Inout_ NET_BUFFER_LIST *Nbl) -{ - *(ULONG_PTR *)&NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[0] |= 1; -} - -static BOOLEAN -TunNblIsCompleted(_In_ NET_BUFFER_LIST *Nbl) -{ - return (ULONG_PTR)(NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[0]) & 1; -} - -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; - LONG64 SentPacketsCount = 0, SentPacketsSize = 0, ErrorPacketsCount = 0, DiscardedPacketsCount = 0; - - /* Measure NBLs. */ - ULONG PacketsCount = 0, RequiredRingSpace = 0; - for (NET_BUFFER_LIST *Nbl = NetBufferLists; Nbl; Nbl = NET_BUFFER_LIST_NEXT_NBL(Nbl)) - { - for (NET_BUFFER *Nb = NET_BUFFER_LIST_FIRST_NB(Nbl); Nb; Nb = NET_BUFFER_NEXT_NB(Nb)) - { - PacketsCount++; - UINT PacketSize = NET_BUFFER_DATA_LENGTH(Nb); - if (PacketSize > TUN_MAX_IP_PACKET_SIZE) - continue; /* The same condition holds down below, where we `goto skipPacket`. */ - RequiredRingSpace += TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize); - } - } - - KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock); - NDIS_STATUS Status; - if ((Status = NDIS_STATUS_PAUSED, !InterlockedGet(&Ctx->Running)) || - (Status = NDIS_STATUS_MEDIA_DISCONNECTED, KeReadStateEvent(&Ctx->Device.Disconnected))) - goto skipNbl; - - TUN_RING *Ring = Ctx->Device.Send.Ring; - ULONG RingCapacity = Ctx->Device.Send.Capacity; - - /* Allocate space for packets in the ring. */ - ULONG RingHead = InterlockedGetU(&Ring->Head); - if (Status = NDIS_STATUS_ADAPTER_NOT_READY, RingHead >= RingCapacity) - goto skipNbl; - - KLOCK_QUEUE_HANDLE LockHandle; - KeAcquireInStackQueuedSpinLock(&Ctx->Device.Send.Lock, &LockHandle); - - ULONG RingTail = Ctx->Device.Send.RingTail; - ASSERT(RingTail < RingCapacity); - - ULONG RingSpace = TUN_RING_WRAP(RingHead - RingTail - TUN_ALIGNMENT, RingCapacity); - if (Status = NDIS_STATUS_BUFFER_OVERFLOW, RingSpace < RequiredRingSpace) - goto cleanupKeReleaseInStackQueuedSpinLock; - - Ctx->Device.Send.RingTail = TUN_RING_WRAP(RingTail + RequiredRingSpace, RingCapacity); - TunNblSetOffsetAndMarkActive(NetBufferLists, Ctx->Device.Send.RingTail); - *(Ctx->Device.Send.ActiveNbls.Head ? &NET_BUFFER_LIST_NEXT_NBL_EX(Ctx->Device.Send.ActiveNbls.Tail) - : &Ctx->Device.Send.ActiveNbls.Head) = NetBufferLists; - Ctx->Device.Send.ActiveNbls.Tail = NetBufferLists; - - KeReleaseInStackQueuedSpinLock(&LockHandle); - - /* Copy packets. */ - for (NET_BUFFER_LIST *Nbl = NetBufferLists; Nbl; Nbl = NET_BUFFER_LIST_NEXT_NBL(Nbl)) - { - for (NET_BUFFER *Nb = NET_BUFFER_LIST_FIRST_NB(Nbl); Nb; Nb = NET_BUFFER_NEXT_NB(Nb)) - { - UINT PacketSize = NET_BUFFER_DATA_LENGTH(Nb); - if (Status = NDIS_STATUS_INVALID_LENGTH, PacketSize > TUN_MAX_IP_PACKET_SIZE) - goto skipPacket; - - TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingTail); - Packet->Size = PacketSize; - void *NbData = NdisGetDataBuffer(Nb, PacketSize, Packet->Data, 1, 0); - if (!NbData) - { - /* The space for the packet has already been allocated in the ring. Write a zero-packet rather than - * fixing the gap in the ring. */ - NdisZeroMemory(Packet->Data, PacketSize); - DiscardedPacketsCount++; - NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_FAILURE; - } - else - { - if (NbData != Packet->Data) - NdisMoveMemory(Packet->Data, NbData, PacketSize); - SentPacketsCount++; - SentPacketsSize += PacketSize; - } - - RingTail = TUN_RING_WRAP(RingTail + TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize), RingCapacity); - continue; - - skipPacket: - ErrorPacketsCount++; - NET_BUFFER_LIST_STATUS(Nbl) = Status; - } - } - ASSERT(RingTail == TunNblGetOffset(NetBufferLists)); - TunNblMarkCompleted(NetBufferLists); - - /* Adjust the ring tail. */ - KeAcquireInStackQueuedSpinLock(&Ctx->Device.Send.Lock, &LockHandle); - while (Ctx->Device.Send.ActiveNbls.Head && TunNblIsCompleted(Ctx->Device.Send.ActiveNbls.Head)) - { - NET_BUFFER_LIST *CompletedNbl = Ctx->Device.Send.ActiveNbls.Head; - Ctx->Device.Send.ActiveNbls.Head = NET_BUFFER_LIST_NEXT_NBL_EX(CompletedNbl); - InterlockedSetU(&Ring->Tail, TunNblGetOffset(CompletedNbl)); - KeSetEvent(Ctx->Device.Send.TailMoved, IO_NETWORK_INCREMENT, FALSE); - NdisMSendNetBufferListsComplete( - Ctx->MiniportAdapterHandle, CompletedNbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); - } - KeReleaseInStackQueuedSpinLock(&LockHandle); - ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); - goto updateStatistics; - -cleanupKeReleaseInStackQueuedSpinLock: - KeReleaseInStackQueuedSpinLock(&LockHandle); -skipNbl: - for (NET_BUFFER_LIST *Nbl = NetBufferLists; Nbl; Nbl = NET_BUFFER_LIST_NEXT_NBL(Nbl)) - NET_BUFFER_LIST_STATUS(Nbl) = Status; - DiscardedPacketsCount += PacketsCount; - ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); - NdisMSendNetBufferListsComplete(Ctx->MiniportAdapterHandle, NetBufferLists, 0); -updateStatistics: - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount); -} - -static MINIPORT_CANCEL_SEND TunCancelSend; -_Use_decl_annotations_ -static VOID -TunCancelSend(NDIS_HANDLE MiniportAdapterContext, PVOID CancelId) -{ -} - -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; - TUN_RING *Ring = Ctx->Device.Receive.Ring; - - LONG64 ReceivedPacketsCount = 0, ReceivedPacketsSize = 0, ErrorPacketsCount = 0; - for (NET_BUFFER_LIST *Nbl = NetBufferLists, *NextNbl; Nbl; Nbl = NextNbl) - { - NextNbl = NET_BUFFER_LIST_NEXT_NBL(Nbl); - - if (NT_SUCCESS(NET_BUFFER_LIST_STATUS(Nbl))) - { - ReceivedPacketsCount++; - ReceivedPacketsSize += NET_BUFFER_LIST_FIRST_NB(Nbl)->DataLength; - } - else - ErrorPacketsCount++; - - TunNblMarkCompleted(Nbl); - for (;;) - { - KLOCK_QUEUE_HANDLE LockHandle; - KeAcquireInStackQueuedSpinLock(&Ctx->Device.Receive.Lock, &LockHandle); - NET_BUFFER_LIST *CompletedNbl = Ctx->Device.Receive.ActiveNbls.Head; - if (!CompletedNbl || !TunNblIsCompleted(CompletedNbl)) - { - KeReleaseInStackQueuedSpinLock(&LockHandle); - break; - } - Ctx->Device.Receive.ActiveNbls.Head = NET_BUFFER_LIST_NEXT_NBL_EX(CompletedNbl); - if (!Ctx->Device.Receive.ActiveNbls.Head) - KeSetEvent(&Ctx->Device.Receive.ActiveNbls.Empty, IO_NO_INCREMENT, FALSE); - KeReleaseInStackQueuedSpinLock(&LockHandle); - InterlockedSetU(&Ring->Head, TunNblGetOffset(CompletedNbl)); - NdisFreeNetBufferList(CompletedNbl); - } - } - - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount); - InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -_Function_class_(KSTART_ROUTINE) -static VOID -TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) -{ - KeSetPriorityThread(KeGetCurrentThread(), 1); - - TUN_RING *Ring = Ctx->Device.Receive.Ring; - ULONG RingCapacity = Ctx->Device.Receive.Capacity; - LARGE_INTEGER Frequency; - KeQueryPerformanceCounter(&Frequency); - ULONG64 SpinMax = Frequency.QuadPart / 1000 / 10; /* 1/10 ms */ - VOID *Events[] = { &Ctx->Device.Disconnected, Ctx->Device.Receive.TailMoved }; - ASSERT(RTL_NUMBER_OF(Events) <= THREAD_WAIT_OBJECTS); - - ULONG RingHead = InterlockedGetU(&Ring->Head); - if (RingHead >= RingCapacity) - goto cleanup; - - while (!KeReadStateEvent(&Ctx->Device.Disconnected)) - { - /* Get next packet from the ring. */ - ULONG RingTail = InterlockedGetU(&Ring->Tail); - if (RingHead == RingTail) - { - LARGE_INTEGER SpinStart = KeQueryPerformanceCounter(NULL); - for (;;) - { - RingTail = InterlockedGetU(&Ring->Tail); - if (RingTail != RingHead) - break; - if (KeReadStateEvent(&Ctx->Device.Disconnected)) - break; - LARGE_INTEGER SpinNow = KeQueryPerformanceCounter(NULL); - if ((ULONG64)SpinNow.QuadPart - (ULONG64)SpinStart.QuadPart >= SpinMax) - break; - ZwYieldExecution(); - } - if (RingHead == RingTail) - { - InterlockedSet(&Ring->Alertable, TRUE); - RingTail = InterlockedGetU(&Ring->Tail); - if (RingHead == RingTail) - { - KeWaitForMultipleObjects( - RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); - InterlockedSet(&Ring->Alertable, FALSE); - continue; - } - InterlockedSet(&Ring->Alertable, FALSE); - KeClearEvent(Ctx->Device.Receive.TailMoved); - } - } - if (RingTail >= RingCapacity) - break; - - ULONG RingContent = TUN_RING_WRAP(RingTail - RingHead, RingCapacity); - if (RingContent < sizeof(TUN_PACKET)) - break; - - TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingHead); - ULONG PacketSize = Packet->Size; - if (PacketSize > TUN_MAX_IP_PACKET_SIZE) - break; - - ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize); - if (AlignedPacketSize > RingContent) - break; - - ULONG NblFlags; - USHORT NblProto; - if (PacketSize >= 20 && Packet->Data[0] >> 4 == 4) - { - NblFlags = NDIS_NBL_FLAGS_IS_IPV4; - NblProto = HTONS(NDIS_ETH_TYPE_IPV4); - } - else if (PacketSize >= 40 && Packet->Data[0] >> 4 == 6) - { - NblFlags = NDIS_NBL_FLAGS_IS_IPV6; - NblProto = HTONS(NDIS_ETH_TYPE_IPV6); - } - else - break; - - RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity); - - NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList( - Ctx->NblPool, 0, 0, Ctx->Device.Receive.Mdl, (ULONG)(Packet->Data - (UCHAR *)Ring), PacketSize); - if (!Nbl) - goto skipNbl; - Nbl->SourceHandle = Ctx->MiniportAdapterHandle; - NdisSetNblFlag(Nbl, NblFlags); - NET_BUFFER_LIST_INFO(Nbl, NetBufferListFrameType) = (PVOID)NblProto; - NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_SUCCESS; - TunNblSetOffsetAndMarkActive(Nbl, RingHead); - - KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock); - if (!InterlockedGet(&Ctx->Running)) - goto cleanupNbl; - - KLOCK_QUEUE_HANDLE LockHandle; - KeAcquireInStackQueuedSpinLock(&Ctx->Device.Receive.Lock, &LockHandle); - if (Ctx->Device.Receive.ActiveNbls.Head) - NET_BUFFER_LIST_NEXT_NBL_EX(Ctx->Device.Receive.ActiveNbls.Tail) = Nbl; - else - { - KeClearEvent(&Ctx->Device.Receive.ActiveNbls.Empty); - Ctx->Device.Receive.ActiveNbls.Head = Nbl; - } - Ctx->Device.Receive.ActiveNbls.Tail = Nbl; - KeReleaseInStackQueuedSpinLock(&LockHandle); - - NdisMIndicateReceiveNetBufferLists( - Ctx->MiniportAdapterHandle, - Nbl, - NDIS_DEFAULT_PORT_NUMBER, - 1, - NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL | NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE); - - ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); - continue; - - cleanupNbl: - ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); - NdisFreeNetBufferList(Nbl); - skipNbl: - InterlockedIncrement64((LONG64 *)&Ctx->Statistics.ifInDiscards); - KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL); - InterlockedSetU(&Ring->Head, RingHead); - } - - /* Wait for all NBLs to return: 1. To prevent race between proceeding and invalidating ring head. 2. To have - * TunDispatchUnregisterBuffers() implicitly wait before releasing ring MDL used by NBL(s). */ - KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL); -cleanup: - InterlockedSetU(&Ring->Head, MAXULONG); -} - -#define IS_POW2(x) ((x) && !((x) & ((x)-1))) - -_IRQL_requires_max_(PASSIVE_LEVEL) -_Must_inspect_result_ -static NTSTATUS -TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp) -{ - NTSTATUS Status = STATUS_ALREADY_INITIALIZED; - IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp); - - if (!ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, FALSE)) - return Status; - - if (Ctx->Device.OwningFileObject) - goto cleanupMutex; - Ctx->Device.OwningFileObject = Stack->FileObject; - - TUN_REGISTER_RINGS *Rrb = Irp->AssociatedIrp.SystemBuffer; - if (Status = STATUS_INVALID_PARAMETER, Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(*Rrb)) - goto cleanupResetOwner; - - Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb->Send.RingSize); - if (Status = STATUS_INVALID_PARAMETER, - (Ctx->Device.Send.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Send.Capacity > TUN_MAX_RING_CAPACITY || - !IS_POW2(Ctx->Device.Send.Capacity) || !Rrb->Send.TailMoved || !Rrb->Send.Ring)) - goto cleanupResetOwner; - - if (!NT_SUCCESS( - Status = ObReferenceObjectByHandle( - Rrb->Send.TailMoved, - /* We will not wait on send ring tail moved event. */ - EVENT_MODIFY_STATE, - *ExEventObjectType, - UserMode, - &Ctx->Device.Send.TailMoved, - NULL))) - goto cleanupResetOwner; - - Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb->Send.Ring, Rrb->Send.RingSize, FALSE, FALSE, NULL); - if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Mdl) - goto cleanupSendTailMoved; - try - { - Status = STATUS_INVALID_USER_BUFFER; - MmProbeAndLockPages(Ctx->Device.Send.Mdl, UserMode, IoWriteAccess); - } - except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupSendMdl; } - - Ctx->Device.Send.Ring = - MmGetSystemAddressForMdlSafe(Ctx->Device.Send.Mdl, NormalPagePriority | MdlMappingNoExecute); - if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Ring) - goto cleanupSendUnlockPages; - - Ctx->Device.Send.RingTail = InterlockedGetU(&Ctx->Device.Send.Ring->Tail); - if (Status = STATUS_INVALID_PARAMETER, Ctx->Device.Send.RingTail >= Ctx->Device.Send.Capacity) - goto cleanupSendUnlockPages; - - Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb->Receive.RingSize); - if (Status = STATUS_INVALID_PARAMETER, - (Ctx->Device.Receive.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Receive.Capacity > TUN_MAX_RING_CAPACITY || - !IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb->Receive.TailMoved || !Rrb->Receive.Ring)) - goto cleanupSendUnlockPages; - - if (!NT_SUCCESS( - Status = ObReferenceObjectByHandle( - Rrb->Receive.TailMoved, - /* We need to clear receive ring TailMoved event on transition to non-alertable state. */ - SYNCHRONIZE | EVENT_MODIFY_STATE, - *ExEventObjectType, - UserMode, - &Ctx->Device.Receive.TailMoved, - NULL))) - goto cleanupSendUnlockPages; - - Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb->Receive.Ring, Rrb->Receive.RingSize, FALSE, FALSE, NULL); - if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Mdl) - goto cleanupReceiveTailMoved; - try - { - Status = STATUS_INVALID_USER_BUFFER; - MmProbeAndLockPages(Ctx->Device.Receive.Mdl, UserMode, IoWriteAccess); - } - except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupReceiveMdl; } - - Ctx->Device.Receive.Ring = - MmGetSystemAddressForMdlSafe(Ctx->Device.Receive.Mdl, NormalPagePriority | MdlMappingNoExecute); - if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Ring) - goto cleanupReceiveUnlockPages; - - KeClearEvent(&Ctx->Device.Disconnected); - - OBJECT_ATTRIBUTES ObjectAttributes; - InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); - if (Status = NDIS_STATUS_FAILURE, - !NT_SUCCESS(PsCreateSystemThread( - &Ctx->Device.Receive.Thread, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, TunProcessReceiveData, Ctx))) - goto cleanupFlagsConnected; - - Ctx->Device.OwningProcessId = PsGetCurrentProcessId(); - InitializeListHead(&Ctx->Device.Entry); - ExAcquireResourceExclusiveLite(&TunDispatchDeviceListLock, TRUE); - InsertTailList(&TunDispatchDeviceList, &Ctx->Device.Entry); - ExReleaseResourceLite(&TunDispatchDeviceListLock); - - ExReleaseResourceLite(&Ctx->Device.RegistrationLock); - TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateConnected); - return STATUS_SUCCESS; - -cleanupFlagsConnected: - KeSetEvent(&Ctx->Device.Disconnected, IO_NO_INCREMENT, FALSE); - ExReleaseSpinLockExclusive( - &Ctx->TransitionLock, - ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */ -cleanupReceiveUnlockPages: - MmUnlockPages(Ctx->Device.Receive.Mdl); -cleanupReceiveMdl: - IoFreeMdl(Ctx->Device.Receive.Mdl); -cleanupReceiveTailMoved: - ObDereferenceObject(Ctx->Device.Receive.TailMoved); -cleanupSendUnlockPages: - MmUnlockPages(Ctx->Device.Send.Mdl); -cleanupSendMdl: - IoFreeMdl(Ctx->Device.Send.Mdl); -cleanupSendTailMoved: - ObDereferenceObject(Ctx->Device.Send.TailMoved); -cleanupResetOwner: - Ctx->Device.OwningFileObject = NULL; -cleanupMutex: - ExReleaseResourceLite(&Ctx->Device.RegistrationLock); - return Status; -} - -#define TUN_FORCE_UNREGISTRATION ((FILE_OBJECT *)-1) -_IRQL_requires_max_(PASSIVE_LEVEL) -static VOID -TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner) -{ - if (!Owner) - return; - ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, TRUE); - if (!Ctx->Device.OwningFileObject || (Owner != TUN_FORCE_UNREGISTRATION && Ctx->Device.OwningFileObject != Owner)) - { - ExReleaseResourceLite(&Ctx->Device.RegistrationLock); - return; - } - Ctx->Device.OwningFileObject = NULL; - - ExAcquireResourceExclusiveLite(&TunDispatchDeviceListLock, TRUE); - RemoveEntryList(&Ctx->Device.Entry); - ExReleaseResourceLite(&TunDispatchDeviceListLock); - - TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected); - - KeSetEvent(&Ctx->Device.Disconnected, IO_NO_INCREMENT, FALSE); - ExReleaseSpinLockExclusive( - &Ctx->TransitionLock, - ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */ - - PKTHREAD ThreadObject; - if (NT_SUCCESS( - ObReferenceObjectByHandle(Ctx->Device.Receive.Thread, SYNCHRONIZE, NULL, KernelMode, &ThreadObject, NULL))) - { - KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL); - ObDereferenceObject(ThreadObject); - } - ZwClose(Ctx->Device.Receive.Thread); - - InterlockedSetU(&Ctx->Device.Send.Ring->Tail, MAXULONG); - KeSetEvent(Ctx->Device.Send.TailMoved, IO_NO_INCREMENT, FALSE); - - MmUnlockPages(Ctx->Device.Receive.Mdl); - IoFreeMdl(Ctx->Device.Receive.Mdl); - ObDereferenceObject(Ctx->Device.Receive.TailMoved); - MmUnlockPages(Ctx->Device.Send.Mdl); - IoFreeMdl(Ctx->Device.Send.Mdl); - ObDereferenceObject(Ctx->Device.Send.TailMoved); - - ExReleaseResourceLite(&Ctx->Device.RegistrationLock); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -static VOID -TunForceHandlesClosed(_Inout_ DEVICE_OBJECT *DeviceObject) -{ - NTSTATUS Status; - PEPROCESS Process; - KAPC_STATE ApcState; - PVOID Object = NULL; - ULONG VerifierFlags = 0; - OBJECT_HANDLE_INFORMATION HandleInfo; - SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL; - - MmIsVerifierEnabled(&VerifierFlags); - - for (ULONG Size = 0, RequestedSize; - (Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) == - STATUS_INFO_LENGTH_MISMATCH; - Size = RequestedSize) - { - if (HandleTable) - ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); - HandleTable = ExAllocatePoolWithTag(PagedPool, RequestedSize, TUN_MEMORY_TAG); - if (!HandleTable) - return; - } - if (!NT_SUCCESS(Status) || !HandleTable) - goto cleanup; - - HANDLE CurrentProcessId = PsGetCurrentProcessId(); - for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index) - { - FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object; - if (!FileObject || FileObject->Type != 5 || FileObject->DeviceObject != DeviceObject) - continue; - HANDLE ProcessId = HandleTable->Handles[Index].UniqueProcessId; - if (ProcessId == CurrentProcessId) - continue; - Status = PsLookupProcessByProcessId(ProcessId, &Process); - if (!NT_SUCCESS(Status)) - continue; - KeStackAttachProcess(Process, &ApcState); - if (!VerifierFlags) - Status = ObReferenceObjectByHandle( - HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo); - if (NT_SUCCESS(Status)) - { - if (VerifierFlags || Object == FileObject) - ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode); - if (!VerifierFlags) - ObfDereferenceObject(Object); - } - KeUnstackDetachProcess(&ApcState); - ObfDereferenceObject(Process); - } -cleanup: - if (HandleTable) - ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); -} - -static NTSTATUS TunInitializeDispatchSecurityDescriptor(VOID) -{ - NTSTATUS Status; - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - SID LocalSystem = { 0 }; - if (!NT_SUCCESS(Status = RtlInitializeSid(&LocalSystem, &NtAuthority, 1))) - return Status; - LocalSystem.SubAuthority[0] = 18; - struct - { - ACL Dacl; - ACCESS_ALLOWED_ACE AceFiller; - SID SidFiller; - } DaclStorage = { 0 }; - if (!NT_SUCCESS(Status = RtlCreateAcl(&DaclStorage.Dacl, sizeof(DaclStorage), ACL_REVISION))) - return Status; - ACCESS_MASK AccessMask = GENERIC_ALL; - RtlMapGenericMask(&AccessMask, IoGetFileObjectGenericMapping()); - if (!NT_SUCCESS(Status = RtlAddAccessAllowedAce(&DaclStorage.Dacl, ACL_REVISION, AccessMask, &LocalSystem))) - return Status; - SECURITY_DESCRIPTOR SecurityDescriptor = { 0 }; - if (!NT_SUCCESS(Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))) - return Status; - if (!NT_SUCCESS(Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, &DaclStorage.Dacl, FALSE))) - return Status; - SecurityDescriptor.Control |= SE_DACL_PROTECTED; - ULONG RequiredBytes = 0; - Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, NULL, &RequiredBytes); - if (Status != STATUS_BUFFER_TOO_SMALL) - return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status; - TunDispatchSecurityDescriptor = ExAllocatePoolWithTag(NonPagedPoolNx, RequiredBytes, TUN_MEMORY_TAG); - if (!TunDispatchSecurityDescriptor) - return STATUS_INSUFFICIENT_RESOURCES; - Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, TunDispatchSecurityDescriptor, &RequiredBytes); - if (!NT_SUCCESS(Status)) - return Status; - return STATUS_SUCCESS; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -static VOID -TunProcessNotification(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) -{ - if (Create) - return; - ExAcquireSharedStarveExclusive(&TunDispatchDeviceListLock, TRUE); - TUN_CTX *Ctx = NULL; - for (LIST_ENTRY *Entry = TunDispatchDeviceList.Flink; Entry != &TunDispatchDeviceList; Entry = Entry->Flink) - { - TUN_CTX *Candidate = CONTAINING_RECORD(Entry, TUN_CTX, Device.Entry); - if (Candidate->Device.OwningProcessId == ProcessId) - { - Ctx = Candidate; - break; - } - } - ExReleaseResourceLite(&TunDispatchDeviceListLock); - if (!Ctx) - return; - - TunUnregisterBuffers(Ctx, TUN_FORCE_UNREGISTRATION); -} - -_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) -static DRIVER_DISPATCH_PAGED TunDispatchDeviceControl; -_Use_decl_annotations_ -static NTSTATUS -TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp) -{ - IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp); - if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS && - Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_FORCE_CLOSE_HANDLES) - return NdisDispatchDeviceControl(DeviceObject, Irp); - - SECURITY_SUBJECT_CONTEXT SubjectContext; - SeCaptureSubjectContext(&SubjectContext); - NTSTATUS Status; - ACCESS_MASK GrantedAccess; - BOOLEAN HasAccess = SeAccessCheck( - TunDispatchSecurityDescriptor, - &SubjectContext, - FALSE, - FILE_WRITE_DATA, - 0, - NULL, - IoGetFileObjectGenericMapping(), - Irp->RequestorMode, - &GrantedAccess, - &Status); - SeReleaseSubjectContext(&SubjectContext); - if (!HasAccess) - goto cleanup; - switch (Stack->Parameters.DeviceIoControl.IoControlCode) - { - case TUN_IOCTL_REGISTER_RINGS: { - KeEnterCriticalRegion(); - ExAcquireResourceSharedLite(&TunDispatchCtxGuard, TRUE); -#pragma warning(suppress : 28175) - TUN_CTX *Ctx = DeviceObject->Reserved; - Status = NDIS_STATUS_ADAPTER_NOT_READY; - if (Ctx) - Status = TunRegisterBuffers(Ctx, Irp); - ExReleaseResourceLite(&TunDispatchCtxGuard); - KeLeaveCriticalRegion(); - break; - } - case TUN_IOCTL_FORCE_CLOSE_HANDLES: - TunForceHandlesClosed(Stack->FileObject->DeviceObject); - Status = STATUS_SUCCESS; - break; - } -cleanup: - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; -} - -_Dispatch_type_(IRP_MJ_CLOSE) -static DRIVER_DISPATCH_PAGED TunDispatchClose; -_Use_decl_annotations_ -static NTSTATUS -TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp) -{ - KeEnterCriticalRegion(); - ExAcquireResourceSharedLite(&TunDispatchCtxGuard, TRUE); -#pragma warning(suppress : 28175) - TUN_CTX *Ctx = DeviceObject->Reserved; - if (Ctx) - TunUnregisterBuffers(Ctx, IoGetCurrentIrpStackLocation(Irp)->FileObject); - ExReleaseResourceLite(&TunDispatchCtxGuard); - KeLeaveCriticalRegion(); - return NdisDispatchClose(DeviceObject, Irp); -} - -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; - InterlockedSet(&Ctx->Running, TRUE); - return NDIS_STATUS_SUCCESS; -} - -static MINIPORT_PAUSE TunPause; -_Use_decl_annotations_ -static NDIS_STATUS -TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters) -{ - TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext; - - InterlockedSet(&Ctx->Running, FALSE); - ExReleaseSpinLockExclusive( - &Ctx->TransitionLock, - ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */ - - KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL); - - return NDIS_STATUS_SUCCESS; -} - -static MINIPORT_DEVICE_PNP_EVENT_NOTIFY TunDevicePnPEventNotify; -_Use_decl_annotations_ -static VOID -TunDevicePnPEventNotify(NDIS_HANDLE MiniportAdapterContext, PNET_DEVICE_PNP_EVENT NetDevicePnPEvent) -{ -} - -static MINIPORT_INITIALIZE TunInitializeEx; -_Use_decl_annotations_ -static NDIS_STATUS -TunInitializeEx( - NDIS_HANDLE MiniportAdapterHandle, - NDIS_HANDLE MiniportDriverContext, - PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters) -{ - NDIS_STATUS Status; - - if (!MiniportAdapterHandle) - return NDIS_STATUS_FAILURE; - -/* Leaking memory 'Ctx'. Note: 'Ctx' is freed in TunHaltEx or on failure. */ -#pragma warning(suppress : 6014) - TUN_CTX *Ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*Ctx), TUN_MEMORY_TAG); - if (!Ctx) - return NDIS_STATUS_FAILURE; - NdisZeroMemory(Ctx, sizeof(*Ctx)); - - Ctx->MiniportAdapterHandle = MiniportAdapterHandle; - - NdisMGetDeviceProperty(MiniportAdapterHandle, NULL, &Ctx->FunctionalDeviceObject, NULL, NULL, NULL); - if (Status = NDIS_STATUS_FAILURE, !Ctx->FunctionalDeviceObject) - goto cleanupFreeCtx; -#pragma warning(suppress : 28175) - ASSERT(!Ctx->FunctionalDeviceObject->Reserved); - /* Reverse engineering indicates that we'd be better off calling - * NdisWdfGetAdapterContextFromAdapterHandle(functional_device), - * which points to our TUN_CTX object directly, but this isn't - * available before Windows 10, so for now we just stick it into - * this reserved field. Revisit this when we drop support for old - * Windows versions. */ -#pragma warning(suppress : 28175) - Ctx->FunctionalDeviceObject->Reserved = Ctx; - - Ctx->Statistics.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - Ctx->Statistics.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1; - Ctx->Statistics.Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; - Ctx->Statistics.SupportedStatistics = - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | - NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | - NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | - NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT; - KeInitializeEvent(&Ctx->Device.Disconnected, NotificationEvent, TRUE); - KeInitializeSpinLock(&Ctx->Device.Send.Lock); - KeInitializeSpinLock(&Ctx->Device.Receive.Lock); - KeInitializeEvent(&Ctx->Device.Receive.ActiveNbls.Empty, NotificationEvent, TRUE); - ExInitializeResourceLite(&Ctx->Device.RegistrationLock); - - NET_BUFFER_LIST_POOL_PARAMETERS NblPoolParameters = { - .Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT, - .Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, - .Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1 }, - .ProtocolId = NDIS_PROTOCOL_ID_DEFAULT, - .fAllocateNetBuffer = TRUE, - .PoolTag = TUN_MEMORY_TAG - }; -/* Leaking memory 'Ctx->NblPool'. Note: 'Ctx->NblPool' is freed in TunHaltEx or on failure. */ -#pragma warning(suppress : 6014) - Ctx->NblPool = NdisAllocateNetBufferListPool(MiniportAdapterHandle, &NblPoolParameters); - if (Status = NDIS_STATUS_FAILURE, !Ctx->NblPool) - goto cleanupFreeCtx; - - NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES AdapterRegistrationAttributes = { - .Header = { .Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES, - .Revision = NdisVersion < NDIS_RUNTIME_VERSION_630 - ? NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1 - : NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_2, - .Size = NdisVersion < NDIS_RUNTIME_VERSION_630 - ? NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1 - : NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_2 }, - .AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND | NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK, - .InterfaceType = NdisInterfaceInternal, - .MiniportAdapterContext = Ctx - }; - if (Status = NDIS_STATUS_FAILURE, - !NT_SUCCESS(NdisMSetMiniportAttributes( - MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterRegistrationAttributes))) - goto cleanupFreeNblPool; - - NDIS_PM_CAPABILITIES PmCapabilities = { - .Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT, - .Revision = NdisVersion < NDIS_RUNTIME_VERSION_630 ? NDIS_PM_CAPABILITIES_REVISION_1 - : NDIS_PM_CAPABILITIES_REVISION_2, - .Size = NdisVersion < NDIS_RUNTIME_VERSION_630 ? NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_1 - : NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_2 }, - .MinMagicPacketWakeUp = NdisDeviceStateUnspecified, - .MinPatternWakeUp = NdisDeviceStateUnspecified, - .MinLinkChangeWakeUp = NdisDeviceStateUnspecified - }; - static NDIS_OID SupportedOids[] = { OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_CURRENT_LOOKAHEAD, - OID_GEN_TRANSMIT_BUFFER_SPACE, - OID_GEN_RECEIVE_BUFFER_SPACE, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_STATISTICS, - OID_GEN_INTERRUPT_MODERATION, - OID_GEN_LINK_PARAMETERS, - OID_PNP_SET_POWER, - OID_PNP_QUERY_POWER }; - NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES AdapterGeneralAttributes = { - .Header = { .Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES, - .Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2, - .Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2 }, - .MediaType = NdisMediumIP, - .PhysicalMediumType = NdisPhysicalMediumUnspecified, - .MtuSize = TUN_MAX_IP_PACKET_SIZE, - .MaxXmitLinkSpeed = TUN_LINK_SPEED, - .MaxRcvLinkSpeed = TUN_LINK_SPEED, - .RcvLinkSpeed = TUN_LINK_SPEED, - .XmitLinkSpeed = TUN_LINK_SPEED, - .MediaConnectState = MediaConnectStateDisconnected, - .LookaheadSize = TUN_MAX_IP_PACKET_SIZE, - .MacOptions = - NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK, - .SupportedPacketFilters = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_MULTICAST | - NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_ALL_LOCAL | - NDIS_PACKET_TYPE_ALL_FUNCTIONAL, - .AccessType = NET_IF_ACCESS_BROADCAST, - .DirectionType = NET_IF_DIRECTION_SENDRECEIVE, - .ConnectionType = NET_IF_CONNECTION_DEDICATED, - .IfType = IF_TYPE_PROP_VIRTUAL, - .IfConnectorPresent = FALSE, - .SupportedStatistics = Ctx->Statistics.SupportedStatistics, - .SupportedPauseFunctions = NdisPauseFunctionsUnsupported, - .AutoNegotiationFlags = - NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED | NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED | - NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED | NDIS_LINK_STATE_PAUSE_FUNCTIONS_AUTO_NEGOTIATED, - .SupportedOidList = SupportedOids, - .SupportedOidListLength = sizeof(SupportedOids), - .PowerManagementCapabilitiesEx = &PmCapabilities - }; - if (Status = NDIS_STATUS_FAILURE, - !NT_SUCCESS(NdisMSetMiniportAttributes( - MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneralAttributes))) - goto cleanupFreeNblPool; - - /* A miniport driver can call NdisMIndicateStatusEx after setting its - * registration attributes even if the driver is still in the context - * of the MiniportInitializeEx function. */ - TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected); - return NDIS_STATUS_SUCCESS; - -cleanupFreeNblPool: - NdisFreeNetBufferListPool(Ctx->NblPool); -cleanupFreeCtx: - ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG); - return Status; -} - -static MINIPORT_HALT TunHaltEx; -_Use_decl_annotations_ -static VOID -TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction) -{ - TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext; - - TunUnregisterBuffers(Ctx, TUN_FORCE_UNREGISTRATION); - - ExReleaseSpinLockExclusive( - &Ctx->TransitionLock, - ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */ - NdisFreeNetBufferListPool(Ctx->NblPool); - - InterlockedSetPointer(&Ctx->MiniportAdapterHandle, NULL); -#pragma warning(suppress : 28175) - InterlockedSetPointer(&Ctx->FunctionalDeviceObject->Reserved, NULL); - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&TunDispatchCtxGuard, TRUE); /* Ensure above change is visible to all readers. */ - ExReleaseResourceLite(&TunDispatchCtxGuard); - KeLeaveCriticalRegion(); - ExDeleteResourceLite(&Ctx->Device.RegistrationLock); - ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG); -} - -static MINIPORT_SHUTDOWN TunShutdownEx; -_Use_decl_annotations_ -static VOID -TunShutdownEx(NDIS_HANDLE MiniportAdapterContext, NDIS_SHUTDOWN_ACTION ShutdownAction) -{ -} - -_IRQL_requires_max_(APC_LEVEL) -_Must_inspect_result_ -static NDIS_STATUS -TunOidQueryWrite(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_ ULONG Value) -{ - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) - { - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG); - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; - return NDIS_STATUS_BUFFER_TOO_SHORT; - } - - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG); - *(ULONG *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = Value; - return NDIS_STATUS_SUCCESS; -} - -_IRQL_requires_max_(APC_LEVEL) -_Must_inspect_result_ -static NDIS_STATUS -TunOidQueryWrite32or64(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_ ULONG64 Value) -{ - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) - { - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; - return NDIS_STATUS_BUFFER_TOO_SHORT; - } - - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG64)) - { - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG); - *(ULONG *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (ULONG)(Value & 0xffffffff); - return NDIS_STATUS_SUCCESS; - } - - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG64); - *(ULONG64 *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = Value; - return NDIS_STATUS_SUCCESS; -} - -_IRQL_requires_max_(APC_LEVEL) -_Must_inspect_result_ -static NDIS_STATUS -TunOidQueryWriteBuf(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_bytecount_(Size) const void *Buf, _In_ ULONG Size) -{ - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < Size) - { - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = Size; - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; - return NDIS_STATUS_BUFFER_TOO_SHORT; - } - - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = Size; - NdisMoveMemory(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, Buf, Size); - return NDIS_STATUS_SUCCESS; -} - -_IRQL_requires_max_(APC_LEVEL) -_Must_inspect_result_ -static NDIS_STATUS -TunOidQuery(_Inout_ TUN_CTX *Ctx, _Inout_ NDIS_OID_REQUEST *OidRequest) -{ - ASSERT( - OidRequest->RequestType == NdisRequestQueryInformation || - OidRequest->RequestType == NdisRequestQueryStatistics); - - switch (OidRequest->DATA.QUERY_INFORMATION.Oid) - { - case OID_GEN_MAXIMUM_TOTAL_SIZE: - case OID_GEN_TRANSMIT_BLOCK_SIZE: - case OID_GEN_RECEIVE_BLOCK_SIZE: - return TunOidQueryWrite(OidRequest, TUN_MAX_IP_PACKET_SIZE); - - case OID_GEN_TRANSMIT_BUFFER_SPACE: - return TunOidQueryWrite(OidRequest, TUN_MAX_RING_CAPACITY); - - case OID_GEN_RECEIVE_BUFFER_SPACE: - return TunOidQueryWrite(OidRequest, TUN_MAX_RING_CAPACITY); - - case OID_GEN_VENDOR_ID: - return TunOidQueryWrite(OidRequest, HTONL(TUN_VENDOR_ID)); - - case OID_GEN_VENDOR_DESCRIPTION: - return TunOidQueryWriteBuf(OidRequest, TUN_VENDOR_NAME, (ULONG)sizeof(TUN_VENDOR_NAME)); - - case OID_GEN_VENDOR_DRIVER_VERSION: - return TunOidQueryWrite(OidRequest, (WINTUN_VERSION_MAJ << 16) | WINTUN_VERSION_MIN); - - case OID_GEN_XMIT_OK: - return TunOidQueryWrite32or64( - OidRequest, - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) + - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) + - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts)); - - case OID_GEN_RCV_OK: - return TunOidQueryWrite32or64( - OidRequest, - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) + - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) + - InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts)); - - case OID_GEN_STATISTICS: - return TunOidQueryWriteBuf(OidRequest, &Ctx->Statistics, (ULONG)sizeof(Ctx->Statistics)); - - case OID_GEN_INTERRUPT_MODERATION: { - static const NDIS_INTERRUPT_MODERATION_PARAMETERS InterruptParameters = { - .Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT, - .Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1, - .Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1 }, - .InterruptModeration = NdisInterruptModerationNotSupported - }; - return TunOidQueryWriteBuf(OidRequest, &InterruptParameters, (ULONG)sizeof(InterruptParameters)); - } - - case OID_PNP_QUERY_POWER: - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; - return NDIS_STATUS_SUCCESS; - } - - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; - 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); - return NDIS_STATUS_SUCCESS; - } - - return NDIS_STATUS_NOT_SUPPORTED; -} - -static MINIPORT_OID_REQUEST TunOidRequest; -_Use_decl_annotations_ -static NDIS_STATUS -TunOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest) -{ - switch (OidRequest->RequestType) - { - case NdisRequestQueryInformation: - case NdisRequestQueryStatistics: - return TunOidQuery(MiniportAdapterContext, OidRequest); - - case NdisRequestSetInformation: - return TunOidSet(MiniportAdapterContext, OidRequest); - - default: - return NDIS_STATUS_INVALID_OID; - } -} - -static MINIPORT_CANCEL_OID_REQUEST TunCancelOidRequest; -_Use_decl_annotations_ -static VOID -TunCancelOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId) -{ -} - -static MINIPORT_DIRECT_OID_REQUEST TunDirectOidRequest; -_Use_decl_annotations_ -static NDIS_STATUS -TunDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest) -{ - switch (OidRequest->RequestType) - { - case NdisRequestQueryInformation: - case NdisRequestQueryStatistics: - case NdisRequestSetInformation: - return NDIS_STATUS_NOT_SUPPORTED; - - default: - return NDIS_STATUS_INVALID_OID; - } -} - -static MINIPORT_CANCEL_DIRECT_OID_REQUEST TunCancelDirectOidRequest; -_Use_decl_annotations_ -static VOID -TunCancelDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId) -{ -} - -static MINIPORT_SYNCHRONOUS_OID_REQUEST TunSynchronousOidRequest; -_Use_decl_annotations_ -static NDIS_STATUS -TunSynchronousOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest) -{ - switch (OidRequest->RequestType) - { - case NdisRequestQueryInformation: - case NdisRequestQueryStatistics: - case NdisRequestSetInformation: - return NDIS_STATUS_NOT_SUPPORTED; - - default: - return NDIS_STATUS_INVALID_OID; - } -} - -static MINIPORT_UNLOAD TunUnload; -_Use_decl_annotations_ -static VOID -TunUnload(PDRIVER_OBJECT DriverObject) -{ - PsSetCreateProcessNotifyRoutine(TunProcessNotification, TRUE); - NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle); - ExDeleteResourceLite(&TunDispatchCtxGuard); - ExDeleteResourceLite(&TunDispatchDeviceListLock); - ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG); -} - -DRIVER_INITIALIZE DriverEntry; -_Use_decl_annotations_ -NTSTATUS -DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath) -{ - NTSTATUS Status; - - if (!NT_SUCCESS(Status = TunInitializeDispatchSecurityDescriptor())) - return Status; - - NdisVersion = NdisGetVersion(); - if (NdisVersion < NDIS_MINIPORT_VERSION_MIN) - return NDIS_STATUS_UNSUPPORTED_REVISION; - if (NdisVersion > NDIS_MINIPORT_VERSION_MAX) - NdisVersion = NDIS_MINIPORT_VERSION_MAX; - - ExInitializeResourceLite(&TunDispatchCtxGuard); - ExInitializeResourceLite(&TunDispatchDeviceListLock); - - NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniport = { - .Header = { .Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS, - .Revision = NdisVersion < NDIS_RUNTIME_VERSION_680 - ? NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2 - : NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_3, - .Size = NdisVersion < NDIS_RUNTIME_VERSION_680 - ? NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2 - : NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_3 }, - - .MajorNdisVersion = (UCHAR)((NdisVersion & 0x00ff0000) >> 16), - .MinorNdisVersion = (UCHAR)(NdisVersion & 0x000000ff), - - .MajorDriverVersion = WINTUN_VERSION_MAJ, - .MinorDriverVersion = WINTUN_VERSION_MIN, - - .InitializeHandlerEx = TunInitializeEx, - .HaltHandlerEx = TunHaltEx, - .UnloadHandler = TunUnload, - .PauseHandler = TunPause, - .RestartHandler = TunRestart, - .OidRequestHandler = TunOidRequest, - .SendNetBufferListsHandler = TunSendNetBufferLists, - .ReturnNetBufferListsHandler = TunReturnNetBufferLists, - .CancelSendHandler = TunCancelSend, - .DevicePnPEventNotifyHandler = TunDevicePnPEventNotify, - .ShutdownHandlerEx = TunShutdownEx, - .CancelOidRequestHandler = TunCancelOidRequest, - .DirectOidRequestHandler = TunDirectOidRequest, - .CancelDirectOidRequestHandler = TunCancelDirectOidRequest, - .SynchronousOidRequestHandler = TunSynchronousOidRequest - }; - - Status = PsSetCreateProcessNotifyRoutine(TunProcessNotification, FALSE); - if (!NT_SUCCESS(Status)) - goto cleanupResources; - - Status = NdisMRegisterMiniportDriver(DriverObject, RegistryPath, NULL, &miniport, &NdisMiniportDriverHandle); - if (!NT_SUCCESS(Status)) - goto cleanupNotifier; - - NdisDispatchDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; - NdisDispatchClose = DriverObject->MajorFunction[IRP_MJ_CLOSE]; - DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TunDispatchDeviceControl; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = TunDispatchClose; - - return STATUS_SUCCESS; - -cleanupNotifier: - PsSetCreateProcessNotifyRoutine(TunProcessNotification, TRUE); -cleanupResources: - ExDeleteResourceLite(&TunDispatchCtxGuard); - ExDeleteResourceLite(&TunDispatchDeviceListLock); - ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG); - return Status; -} |