2019-03-08 22:33:15 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0
|
|
|
|
*
|
2020-10-31 11:58:59 +01:00
|
|
|
* Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
|
2019-03-08 22:33:15 +01:00
|
|
|
*/
|
|
|
|
|
2019-05-30 21:39:33 +02:00
|
|
|
#include <ntifs.h>
|
2019-03-08 22:33:15 +01:00
|
|
|
#include <wdm.h>
|
|
|
|
#include <wdmsec.h>
|
|
|
|
#include <ndis.h>
|
|
|
|
#include <ntstrsafe.h>
|
2019-07-23 08:37:10 +02:00
|
|
|
#include "undocumented.h"
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-06-27 15:08:29 +02:00
|
|
|
#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 */
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
#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
|
2019-06-27 15:08:29 +02:00
|
|
|
#define TUN_LINK_SPEED 100000000000ULL /* 100gbps */
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
/* Memory alignment of packets and rings */
|
|
|
|
#define TUN_ALIGNMENT sizeof(ULONG)
|
2019-07-17 11:53:25 +02:00
|
|
|
#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)))
|
2019-07-08 11:01:39 +02:00
|
|
|
/* 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))
|
2019-06-07 12:23:44 +02:00
|
|
|
|
|
|
|
#if REG_DWORD == REG_DWORD_BIG_ENDIAN
|
2019-07-29 12:39:47 +02:00
|
|
|
# define HTONS(x) ((USHORT)(x))
|
|
|
|
# define HTONL(x) ((ULONG)(x))
|
2019-06-07 12:23:44 +02:00
|
|
|
#elif REG_DWORD == REG_DWORD_LITTLE_ENDIAN
|
2019-07-29 12:39:47 +02:00
|
|
|
# define HTONS(x) ((((USHORT)(x)&0x00ff) << 8) | (((USHORT)(x)&0xff00) >> 8))
|
|
|
|
# define HTONL(x) \
|
2019-06-26 19:37:29 +02:00
|
|
|
((((ULONG)(x)&0x000000ff) << 24) | (((ULONG)(x)&0x0000ff00) << 8) | (((ULONG)(x)&0x00ff0000) >> 8) | \
|
|
|
|
(((ULONG)(x)&0xff000000) >> 24))
|
2019-06-07 12:23:44 +02:00
|
|
|
#else
|
2019-06-26 14:52:38 +02:00
|
|
|
# error "Unable to determine endianess"
|
2019-06-07 12:23:44 +02:00
|
|
|
#endif
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-29 12:39:47 +02:00
|
|
|
#define TUN_MEMORY_TAG HTONL('wtun')
|
2019-07-03 12:43:55 +02:00
|
|
|
|
2019-06-26 14:52:38 +02:00
|
|
|
typedef struct _TUN_PACKET
|
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
/* Size of packet data (TUN_MAX_IP_PACKET_SIZE max) */
|
|
|
|
ULONG Size;
|
|
|
|
|
|
|
|
/* Packet data */
|
|
|
|
UCHAR _Field_size_bytes_(Size)
|
|
|
|
Data[];
|
2019-03-08 22:33:15 +01:00
|
|
|
} TUN_PACKET;
|
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
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;
|
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
#ifdef _WIN64
|
|
|
|
typedef struct _TUN_REGISTER_RINGS_32
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
/* Size of the ring */
|
|
|
|
ULONG RingSize;
|
|
|
|
|
|
|
|
/* 32-bit addres of client allocated ring */
|
|
|
|
ULONG 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. */
|
|
|
|
ULONG TailMoved;
|
|
|
|
} Send, Receive;
|
|
|
|
} TUN_REGISTER_RINGS_32;
|
|
|
|
#endif
|
|
|
|
|
2019-07-23 08:37:10 +02:00
|
|
|
/* Register rings hosted by the client.
|
2019-07-08 11:01:39 +02:00
|
|
|
* 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. */
|
2019-07-22 09:36:21 +02:00
|
|
|
#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
|
2019-07-23 08:37:10 +02:00
|
|
|
/* Force close all open handles to allow for updating. */
|
2019-07-22 09:36:21 +02:00
|
|
|
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-06-26 14:52:38 +02:00
|
|
|
typedef struct _TUN_CTX
|
|
|
|
{
|
2019-07-23 15:19:37 +02:00
|
|
|
volatile LONG Running;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
/* 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(). */
|
2019-06-26 14:52:38 +02:00
|
|
|
EX_SPIN_LOCK TransitionLock;
|
|
|
|
|
2019-06-27 15:08:29 +02:00
|
|
|
NDIS_HANDLE MiniportAdapterHandle; /* This is actually a pointer to NDIS_MINIPORT_BLOCK struct. */
|
2019-07-18 12:25:37 +02:00
|
|
|
DEVICE_OBJECT *FunctionalDeviceObject;
|
2019-06-26 14:52:38 +02:00
|
|
|
NDIS_STATISTICS_INFO Statistics;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
2019-10-06 11:38:44 +02:00
|
|
|
LIST_ENTRY Entry;
|
|
|
|
ERESOURCE RegistrationLock;
|
|
|
|
FILE_OBJECT *OwningFileObject;
|
|
|
|
HANDLE OwningProcessId;
|
2019-07-17 14:40:19 +02:00
|
|
|
KEVENT Disconnected;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
MDL *Mdl;
|
|
|
|
TUN_RING *Ring;
|
|
|
|
ULONG Capacity;
|
|
|
|
KEVENT *TailMoved;
|
2019-06-26 14:52:38 +02:00
|
|
|
KSPIN_LOCK Lock;
|
2019-07-18 19:43:40 +02:00
|
|
|
ULONG RingTail;
|
2019-07-17 11:53:25 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST *Head, *Tail;
|
|
|
|
} ActiveNbls;
|
2019-07-08 11:01:39 +02:00
|
|
|
} Send;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
MDL *Mdl;
|
|
|
|
TUN_RING *Ring;
|
|
|
|
ULONG Capacity;
|
|
|
|
KEVENT *TailMoved;
|
|
|
|
HANDLE Thread;
|
2019-07-18 13:45:30 +02:00
|
|
|
KSPIN_LOCK Lock;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST *Head, *Tail;
|
2019-07-31 21:53:20 +02:00
|
|
|
KEVENT Empty;
|
2019-07-18 13:45:30 +02:00
|
|
|
} ActiveNbls;
|
2019-07-08 11:01:39 +02:00
|
|
|
} Receive;
|
2019-06-26 14:52:38 +02:00
|
|
|
} Device;
|
|
|
|
|
2019-07-05 13:23:29 +02:00
|
|
|
NDIS_HANDLE NblPool;
|
2019-03-08 22:33:15 +01:00
|
|
|
} TUN_CTX;
|
|
|
|
|
2019-04-03 03:01:28 +02:00
|
|
|
static UINT NdisVersion;
|
2019-05-31 00:50:07 +02:00
|
|
|
static NDIS_HANDLE NdisMiniportDriverHandle;
|
2019-07-18 14:41:04 +02:00
|
|
|
static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose;
|
2019-10-06 11:38:44 +02:00
|
|
|
static ERESOURCE TunDispatchCtxGuard, TunDispatchDeviceListLock;
|
|
|
|
static RTL_STATIC_LIST_HEAD(TunDispatchDeviceList);
|
2019-07-18 19:43:40 +02:00
|
|
|
static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor;
|
2019-03-08 22:33:15 +01:00
|
|
|
|
|
|
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunIndicateStatus(_In_ NDIS_HANDLE MiniportAdapterHandle, _In_ NDIS_MEDIA_CONNECT_STATE MediaConnectState)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
NDIS_LINK_STATE State = { .Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT,
|
2019-06-26 18:59:02 +02:00
|
|
|
.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 };
|
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
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) };
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
NdisMIndicateStatusEx(MiniportAdapterHandle, &Indication);
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
/* 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])
|
|
|
|
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-18 13:45:30 +02:00
|
|
|
TunNblSetOffsetAndMarkActive(_Inout_ NET_BUFFER_LIST *Nbl, _In_ ULONG Offset)
|
2019-07-17 11:53:25 +02:00
|
|
|
{
|
2019-07-18 13:45:30 +02:00
|
|
|
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;
|
2019-07-17 11:53:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG
|
2019-07-18 13:45:30 +02:00
|
|
|
TunNblGetOffset(_In_ NET_BUFFER_LIST *Nbl)
|
2019-07-17 11:53:25 +02:00
|
|
|
{
|
|
|
|
return (ULONG)((ULONG_PTR)(NET_BUFFER_LIST_MINIPORT_RESERVED(Nbl)[0]) & ~((ULONG_PTR)TUN_ALIGNMENT - 1));
|
|
|
|
}
|
|
|
|
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-17 11:53:25 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
static MINIPORT_SEND_NET_BUFFER_LISTS TunSendNetBufferLists;
|
2019-03-27 09:00:19 +01:00
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-08 11:01:39 +02:00
|
|
|
TunSendNetBufferLists(
|
|
|
|
NDIS_HANDLE MiniportAdapterContext,
|
|
|
|
NET_BUFFER_LIST *NetBufferLists,
|
|
|
|
NDIS_PORT_NUMBER PortNumber,
|
|
|
|
ULONG SendFlags)
|
2019-03-27 09:00:19 +01:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
|
2019-07-17 11:53:25 +02:00
|
|
|
LONG64 SentPacketsCount = 0, SentPacketsSize = 0, ErrorPacketsCount = 0, DiscardedPacketsCount = 0;
|
2019-03-27 09:00:19 +01:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
/* Measure NBLs. */
|
|
|
|
ULONG PacketsCount = 0, RequiredRingSpace = 0;
|
|
|
|
for (NET_BUFFER_LIST *Nbl = NetBufferLists; Nbl; Nbl = NET_BUFFER_LIST_NEXT_NBL(Nbl))
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
for (NET_BUFFER *Nb = NET_BUFFER_LIST_FIRST_NB(Nbl); Nb; Nb = NET_BUFFER_NEXT_NB(Nb))
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-17 11:53:25 +02:00
|
|
|
PacketsCount++;
|
|
|
|
UINT PacketSize = NET_BUFFER_DATA_LENGTH(Nb);
|
2019-12-10 14:38:41 +01:00
|
|
|
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);
|
2019-07-17 11:53:25 +02:00
|
|
|
}
|
2019-12-10 09:18:13 +01:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
|
|
|
|
NDIS_STATUS Status;
|
2020-04-25 01:47:45 +02:00
|
|
|
if ((Status = NDIS_STATUS_PAUSED, !ReadAcquire(&Ctx->Running)) ||
|
2019-12-10 09:18:13 +01:00
|
|
|
(Status = NDIS_STATUS_MEDIA_DISCONNECTED, KeReadStateEvent(&Ctx->Device.Disconnected)))
|
|
|
|
goto skipNbl;
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
TUN_RING *Ring = Ctx->Device.Send.Ring;
|
|
|
|
ULONG RingCapacity = Ctx->Device.Send.Capacity;
|
2019-07-18 08:55:12 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
/* Allocate space for packets in the ring. */
|
2020-04-25 01:47:45 +02:00
|
|
|
ULONG RingHead = ReadULongAcquire(&Ring->Head);
|
2019-12-10 09:18:13 +01:00
|
|
|
if (Status = NDIS_STATUS_ADAPTER_NOT_READY, RingHead >= RingCapacity)
|
|
|
|
goto skipNbl;
|
2019-07-17 11:53:25 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
KLOCK_QUEUE_HANDLE LockHandle;
|
|
|
|
KeAcquireInStackQueuedSpinLock(&Ctx->Device.Send.Lock, &LockHandle);
|
2019-07-17 11:53:25 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
ULONG RingTail = Ctx->Device.Send.RingTail;
|
|
|
|
ASSERT(RingTail < RingCapacity);
|
2019-07-17 11:53:25 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
ULONG RingSpace = TUN_RING_WRAP(RingHead - RingTail - TUN_ALIGNMENT, RingCapacity);
|
|
|
|
if (Status = NDIS_STATUS_BUFFER_OVERFLOW, RingSpace < RequiredRingSpace)
|
|
|
|
goto cleanupKeReleaseInStackQueuedSpinLock;
|
2019-07-17 11:53:25 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
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;
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
KeReleaseInStackQueuedSpinLock(&LockHandle);
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
/* Copy packets. */
|
|
|
|
for (NET_BUFFER_LIST *Nbl = NetBufferLists; Nbl; Nbl = NET_BUFFER_LIST_NEXT_NBL(Nbl))
|
|
|
|
{
|
2019-07-17 11:53:25 +02:00
|
|
|
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;
|
2019-07-08 11:01:39 +02:00
|
|
|
|
|
|
|
TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingTail);
|
|
|
|
Packet->Size = PacketSize;
|
|
|
|
void *NbData = NdisGetDataBuffer(Nb, PacketSize, Packet->Data, 1, 0);
|
|
|
|
if (!NbData)
|
2019-07-17 11:53:25 +02:00
|
|
|
{
|
2019-07-18 14:45:34 +02:00
|
|
|
/* 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);
|
2019-07-17 11:53:25 +02:00
|
|
|
DiscardedPacketsCount++;
|
2019-12-10 09:18:13 +01:00
|
|
|
NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_FAILURE;
|
2019-07-17 11:53:25 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (NbData != Packet->Data)
|
|
|
|
NdisMoveMemory(Packet->Data, NbData, PacketSize);
|
|
|
|
SentPacketsCount++;
|
|
|
|
SentPacketsSize += PacketSize;
|
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-07-17 11:53:25 +02:00
|
|
|
RingTail = TUN_RING_WRAP(RingTail + TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize), RingCapacity);
|
2019-06-26 14:52:38 +02:00
|
|
|
continue;
|
|
|
|
|
2019-07-17 11:53:25 +02:00
|
|
|
skipPacket:
|
|
|
|
ErrorPacketsCount++;
|
2019-07-08 11:01:39 +02:00
|
|
|
NET_BUFFER_LIST_STATUS(Nbl) = Status;
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
2019-12-10 09:18:13 +01:00
|
|
|
}
|
|
|
|
ASSERT(RingTail == TunNblGetOffset(NetBufferLists));
|
|
|
|
TunNblMarkCompleted(NetBufferLists);
|
2019-07-17 11:53:25 +02:00
|
|
|
|
2019-12-10 09:18:13 +01:00
|
|
|
/* 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);
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteULongRelease(&Ring->Tail, TunNblGetOffset(CompletedNbl));
|
2019-12-10 09:18:13 +01:00
|
|
|
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))
|
2019-07-17 11:53:25 +02:00
|
|
|
NET_BUFFER_LIST_STATUS(Nbl) = Status;
|
2019-12-10 14:35:49 +01:00
|
|
|
DiscardedPacketsCount += PacketsCount;
|
2019-12-10 09:18:13 +01:00
|
|
|
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
|
|
|
|
NdisMSendNetBufferListsComplete(Ctx->MiniportAdapterHandle, NetBufferLists, 0);
|
|
|
|
updateStatistics:
|
2020-04-25 01:47:45 +02:00
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount);
|
2019-03-27 09:00:19 +01:00
|
|
|
}
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
static MINIPORT_CANCEL_SEND TunCancelSend;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-08 11:01:39 +02:00
|
|
|
TunCancelSend(NDIS_HANDLE MiniportAdapterContext, PVOID CancelId)
|
2019-03-27 09:00:19 +01:00
|
|
|
{
|
|
|
|
}
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
static MINIPORT_RETURN_NET_BUFFER_LISTS TunReturnNetBufferLists;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-08 11:01:39 +02:00
|
|
|
TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST NetBufferLists, ULONG ReturnFlags)
|
2019-04-02 13:41:02 +02:00
|
|
|
{
|
2019-07-18 13:45:30 +02:00
|
|
|
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
|
|
|
|
TUN_RING *Ring = Ctx->Device.Receive.Ring;
|
|
|
|
|
2019-08-02 12:03:10 +02:00
|
|
|
LONG64 ReceivedPacketsCount = 0, ReceivedPacketsSize = 0, ErrorPacketsCount = 0;
|
2019-07-18 13:45:30 +02:00
|
|
|
for (NET_BUFFER_LIST *Nbl = NetBufferLists, *NextNbl; Nbl; Nbl = NextNbl)
|
|
|
|
{
|
|
|
|
NextNbl = NET_BUFFER_LIST_NEXT_NBL(Nbl);
|
|
|
|
|
2019-08-02 12:03:10 +02:00
|
|
|
if (NT_SUCCESS(NET_BUFFER_LIST_STATUS(Nbl)))
|
2019-07-18 13:45:30 +02:00
|
|
|
{
|
2019-08-02 12:03:10 +02:00
|
|
|
ReceivedPacketsCount++;
|
|
|
|
ReceivedPacketsSize += NET_BUFFER_LIST_FIRST_NB(Nbl)->DataLength;
|
2019-07-18 13:45:30 +02:00
|
|
|
}
|
|
|
|
else
|
2019-08-02 12:03:10 +02:00
|
|
|
ErrorPacketsCount++;
|
2019-07-18 13:45:30 +02:00
|
|
|
|
|
|
|
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);
|
2019-08-02 12:03:10 +02:00
|
|
|
if (!Ctx->Device.Receive.ActiveNbls.Head)
|
|
|
|
KeSetEvent(&Ctx->Device.Receive.ActiveNbls.Empty, IO_NO_INCREMENT, FALSE);
|
2019-07-18 13:45:30 +02:00
|
|
|
KeReleaseInStackQueuedSpinLock(&LockHandle);
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteULongRelease(&Ring->Head, TunNblGetOffset(CompletedNbl));
|
2019-07-18 13:45:30 +02:00
|
|
|
NdisFreeNetBufferList(CompletedNbl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount);
|
|
|
|
InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount);
|
2019-04-02 13:41:02 +02:00
|
|
|
}
|
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
|
|
_Function_class_(KSTART_ROUTINE)
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-08 11:01:39 +02:00
|
|
|
TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
|
2019-03-27 09:00:19 +01:00
|
|
|
{
|
2019-08-03 22:43:16 +02:00
|
|
|
KeSetPriorityThread(KeGetCurrentThread(), 1);
|
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
TUN_RING *Ring = Ctx->Device.Receive.Ring;
|
|
|
|
ULONG RingCapacity = Ctx->Device.Receive.Capacity;
|
2019-08-04 12:18:42 +02:00
|
|
|
LARGE_INTEGER Frequency;
|
|
|
|
KeQueryPerformanceCounter(&Frequency);
|
|
|
|
ULONG64 SpinMax = Frequency.QuadPart / 1000 / 10; /* 1/10 ms */
|
2019-07-17 14:40:19 +02:00
|
|
|
VOID *Events[] = { &Ctx->Device.Disconnected, Ctx->Device.Receive.TailMoved };
|
|
|
|
ASSERT(RTL_NUMBER_OF(Events) <= THREAD_WAIT_OBJECTS);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
ULONG RingHead = ReadULongAcquire(&Ring->Head);
|
2019-07-18 14:51:15 +02:00
|
|
|
if (RingHead >= RingCapacity)
|
|
|
|
goto cleanup;
|
|
|
|
|
2019-07-17 14:40:19 +02:00
|
|
|
while (!KeReadStateEvent(&Ctx->Device.Disconnected))
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
/* Get next packet from the ring. */
|
2020-04-25 01:47:45 +02:00
|
|
|
ULONG RingTail = ReadULongAcquire(&Ring->Tail);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (RingHead == RingTail)
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-08-04 12:18:42 +02:00
|
|
|
LARGE_INTEGER SpinStart = KeQueryPerformanceCounter(NULL);
|
2019-07-16 18:09:17 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2020-04-25 01:47:45 +02:00
|
|
|
RingTail = ReadULongAcquire(&Ring->Tail);
|
2019-07-16 18:09:17 +02:00
|
|
|
if (RingTail != RingHead)
|
|
|
|
break;
|
2019-07-17 14:40:19 +02:00
|
|
|
if (KeReadStateEvent(&Ctx->Device.Disconnected))
|
2019-07-16 18:09:17 +02:00
|
|
|
break;
|
2019-08-04 12:18:42 +02:00
|
|
|
LARGE_INTEGER SpinNow = KeQueryPerformanceCounter(NULL);
|
2019-07-19 08:56:15 +02:00
|
|
|
if ((ULONG64)SpinNow.QuadPart - (ULONG64)SpinStart.QuadPart >= SpinMax)
|
2019-07-16 18:09:17 +02:00
|
|
|
break;
|
2019-08-03 22:43:16 +02:00
|
|
|
ZwYieldExecution();
|
2019-07-16 18:09:17 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
if (RingHead == RingTail)
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteRelease(&Ring->Alertable, TRUE);
|
|
|
|
RingTail = ReadULongAcquire(&Ring->Tail);
|
2019-07-16 18:09:17 +02:00
|
|
|
if (RingHead == RingTail)
|
|
|
|
{
|
2019-07-18 12:25:37 +02:00
|
|
|
KeWaitForMultipleObjects(
|
|
|
|
RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteRelease(&Ring->Alertable, FALSE);
|
2019-07-16 18:09:17 +02:00
|
|
|
continue;
|
|
|
|
}
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteRelease(&Ring->Alertable, FALSE);
|
2019-07-16 18:09:17 +02:00
|
|
|
KeClearEvent(Ctx->Device.Receive.TailMoved);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
if (RingTail >= RingCapacity)
|
|
|
|
break;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
ULONG RingContent = TUN_RING_WRAP(RingTail - RingHead, RingCapacity);
|
|
|
|
if (RingContent < sizeof(TUN_PACKET))
|
|
|
|
break;
|
|
|
|
|
|
|
|
TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingHead);
|
2020-11-09 22:21:12 +01:00
|
|
|
ULONG PacketSize = *(volatile ULONG *)&Packet->Size;
|
2019-07-08 11:01:39 +02:00
|
|
|
if (PacketSize > TUN_MAX_IP_PACKET_SIZE)
|
|
|
|
break;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
|
|
|
|
if (AlignedPacketSize > RingContent)
|
|
|
|
break;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
ULONG NblFlags;
|
|
|
|
USHORT NblProto;
|
|
|
|
if (PacketSize >= 20 && Packet->Data[0] >> 4 == 4)
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
NblFlags = NDIS_NBL_FLAGS_IS_IPV4;
|
2019-07-29 12:39:47 +02:00
|
|
|
NblProto = HTONS(NDIS_ETH_TYPE_IPV4);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
else if (PacketSize >= 40 && Packet->Data[0] >> 4 == 6)
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
NblFlags = NDIS_NBL_FLAGS_IS_IPV6;
|
2019-07-29 12:39:47 +02:00
|
|
|
NblProto = HTONS(NDIS_ETH_TYPE_IPV6);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
else
|
|
|
|
break;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-18 13:45:30 +02:00
|
|
|
RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
|
driver: use partial MDL for slicing ring, rather than NB's DataOffset
Providing the DataOffset member of the NBL allocation function or
setting that member in the NB header indicates to NDIS not only that the
data starts at that offset, but that there's that amount of space
*available for it to use as it wants* before that offset. This meant
that NDIS was allowed to scribble data before the packet.
This was bounded by the size of the ring, so there was never any risk of
memory corruption, and since the ring is shared by userspace as well as
the rest of the kernel, we've always taken care of reading from it
closely, checking all values, and erroring out on corruption of the
ring. So, if NDIS wrote before the first packet, this would wind up
corrupting the RingTail and Alertable fields of the ring. The receiver
thread would then notice this, error out, and set the RingHead to
MAXULONG on its way out the door, so that userspace can detect it. And
indeed wintun.dll then started returning EOF from its write function.
Mostly this was not an issue, because we're not expecting for data to be
pushed on the head of a packet on ingress. But WSL2's Hyper-V driver is
actually pushing an ethernet header onto the front of the packet before
passing it off to Linux. Practically speaking, this manifested itself in
the RingTail and Alertable fields having Linux's MAC address! And then
the adapter would be EOF'd. This was reported as happening after WSL2
sends the *first* packet, but not others, which makes sense, because it
has to be at the beginning in order to corrupt those fields.
This fixes the problem by simply using a new MDL for the span we want,
instead of using the misunderstood DataOffset field. In order to not
need to keep track of memory allocations, we allocate the MDL as part of
the NBL's context area. And in order to avoid additional mappings, we
use IoBuildPartialMdl, which returns an MDL_PARTIAL, which does not have
an additional mapping that needs to be freed or unmapped.
After making this change, WSL2 no longer appears to halt the adapter,
and all works well.
Fixes: be8d2cb ("Avoid allocating second MDL")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-12-12 15:20:11 +01:00
|
|
|
MDL *Mdl;
|
|
|
|
NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, sizeof(*Mdl), 0, NULL, 0, 0);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (!Nbl)
|
2019-08-02 12:03:10 +02:00
|
|
|
goto skipNbl;
|
driver: use partial MDL for slicing ring, rather than NB's DataOffset
Providing the DataOffset member of the NBL allocation function or
setting that member in the NB header indicates to NDIS not only that the
data starts at that offset, but that there's that amount of space
*available for it to use as it wants* before that offset. This meant
that NDIS was allowed to scribble data before the packet.
This was bounded by the size of the ring, so there was never any risk of
memory corruption, and since the ring is shared by userspace as well as
the rest of the kernel, we've always taken care of reading from it
closely, checking all values, and erroring out on corruption of the
ring. So, if NDIS wrote before the first packet, this would wind up
corrupting the RingTail and Alertable fields of the ring. The receiver
thread would then notice this, error out, and set the RingHead to
MAXULONG on its way out the door, so that userspace can detect it. And
indeed wintun.dll then started returning EOF from its write function.
Mostly this was not an issue, because we're not expecting for data to be
pushed on the head of a packet on ingress. But WSL2's Hyper-V driver is
actually pushing an ethernet header onto the front of the packet before
passing it off to Linux. Practically speaking, this manifested itself in
the RingTail and Alertable fields having Linux's MAC address! And then
the adapter would be EOF'd. This was reported as happening after WSL2
sends the *first* packet, but not others, which makes sense, because it
has to be at the beginning in order to corrupt those fields.
This fixes the problem by simply using a new MDL for the span we want,
instead of using the misunderstood DataOffset field. In order to not
need to keep track of memory allocations, we allocate the MDL as part of
the NBL's context area. And in order to avoid additional mappings, we
use IoBuildPartialMdl, which returns an MDL_PARTIAL, which does not have
an additional mapping that needs to be freed or unmapped.
After making this change, WSL2 no longer appears to halt the adapter,
and all works well.
Fixes: be8d2cb ("Avoid allocating second MDL")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-12-12 15:20:11 +01:00
|
|
|
Mdl = (MDL *)NET_BUFFER_LIST_CONTEXT_DATA_START(Nbl);
|
|
|
|
IoBuildPartialMdl(
|
|
|
|
Ctx->Device.Receive.Mdl,
|
|
|
|
Mdl,
|
|
|
|
(UCHAR *)MmGetMdlVirtualAddress(Ctx->Device.Receive.Mdl) + (ULONG)(Packet->Data - (UCHAR *)Ring),
|
|
|
|
PacketSize);
|
|
|
|
NET_BUFFER *Nb = NET_BUFFER_LIST_FIRST_NB(Nbl);
|
|
|
|
NET_BUFFER_FIRST_MDL(Nb) = NET_BUFFER_CURRENT_MDL(Nb) = Mdl;
|
|
|
|
NET_BUFFER_DATA_LENGTH(Nb) = PacketSize;
|
|
|
|
NET_BUFFER_DATA_OFFSET(Nb) = NET_BUFFER_CURRENT_MDL_OFFSET(Nb) = 0;
|
2019-07-08 11:01:39 +02:00
|
|
|
Nbl->SourceHandle = Ctx->MiniportAdapterHandle;
|
|
|
|
NdisSetNblFlag(Nbl, NblFlags);
|
|
|
|
NET_BUFFER_LIST_INFO(Nbl, NetBufferListFrameType) = (PVOID)NblProto;
|
|
|
|
NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_SUCCESS;
|
2019-07-18 13:45:30 +02:00
|
|
|
TunNblSetOffsetAndMarkActive(Nbl, RingHead);
|
2019-06-07 12:23:44 +02:00
|
|
|
|
2019-07-18 14:51:15 +02:00
|
|
|
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
|
2020-04-25 01:47:45 +02:00
|
|
|
if (!ReadAcquire(&Ctx->Running))
|
2019-08-02 12:03:10 +02:00
|
|
|
goto cleanupNbl;
|
2019-07-18 13:45:30 +02:00
|
|
|
|
2019-08-02 12:03:10 +02:00
|
|
|
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
|
|
|
|
{
|
2019-07-31 21:53:20 +02:00
|
|
|
KeClearEvent(&Ctx->Device.Receive.ActiveNbls.Empty);
|
2019-08-02 12:03:10 +02:00
|
|
|
Ctx->Device.Receive.ActiveNbls.Head = Nbl;
|
|
|
|
}
|
|
|
|
Ctx->Device.Receive.ActiveNbls.Tail = Nbl;
|
|
|
|
KeReleaseInStackQueuedSpinLock(&LockHandle);
|
2019-06-07 12:23:44 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
NdisMIndicateReceiveNetBufferLists(
|
|
|
|
Ctx->MiniportAdapterHandle,
|
|
|
|
Nbl,
|
|
|
|
NDIS_DEFAULT_PORT_NUMBER,
|
|
|
|
1,
|
2019-07-18 13:45:30 +02:00
|
|
|
NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL | NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE);
|
|
|
|
|
2019-07-18 14:51:15 +02:00
|
|
|
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
|
2019-07-18 13:45:30 +02:00
|
|
|
continue;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-08-02 12:03:10 +02:00
|
|
|
cleanupNbl:
|
2019-07-18 14:51:15 +02:00
|
|
|
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
|
2019-08-02 12:03:10 +02:00
|
|
|
NdisFreeNetBufferList(Nbl);
|
|
|
|
skipNbl:
|
2020-04-25 01:47:45 +02:00
|
|
|
InterlockedIncrementNoFence64((LONG64 *)&Ctx->Statistics.ifInDiscards);
|
2019-08-02 12:03:10 +02:00
|
|
|
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteULongRelease(&Ring->Head, RingHead);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
|
|
|
|
2019-07-18 13:45:30 +02:00
|
|
|
/* 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). */
|
2019-07-31 21:53:20 +02:00
|
|
|
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
|
2019-07-18 14:51:15 +02:00
|
|
|
cleanup:
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteULongRelease(&Ring->Head, MAXULONG);
|
2019-06-07 12:23:44 +02:00
|
|
|
}
|
|
|
|
|
2019-07-19 08:56:15 +02:00
|
|
|
#define IS_POW2(x) ((x) && !((x) & ((x)-1)))
|
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
2019-04-09 13:16:40 +02:00
|
|
|
_Must_inspect_result_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NTSTATUS
|
2019-07-18 12:25:37 +02:00
|
|
|
TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-10-06 11:38:44 +02:00
|
|
|
NTSTATUS Status = STATUS_ALREADY_INITIALIZED;
|
2019-07-03 14:21:32 +02:00
|
|
|
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-10-06 11:38:44 +02:00
|
|
|
if (!ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, FALSE))
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
if (Ctx->Device.OwningFileObject)
|
|
|
|
goto cleanupMutex;
|
|
|
|
Ctx->Device.OwningFileObject = Stack->FileObject;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
TUN_REGISTER_RINGS Rrb;
|
|
|
|
if (Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(Rrb))
|
|
|
|
NdisMoveMemory(&Rrb, Irp->AssociatedIrp.SystemBuffer, sizeof(Rrb));
|
|
|
|
#ifdef _WIN64
|
|
|
|
else if (
|
|
|
|
IoIs32bitProcess(Irp) && Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(TUN_REGISTER_RINGS_32))
|
|
|
|
{
|
|
|
|
TUN_REGISTER_RINGS_32 *Rrb32 = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Rrb.Send.RingSize = Rrb32->Send.RingSize;
|
|
|
|
Rrb.Send.Ring = (TUN_RING *)Rrb32->Send.Ring;
|
|
|
|
Rrb.Send.TailMoved = (HANDLE)Rrb32->Send.TailMoved;
|
|
|
|
Rrb.Receive.RingSize = Rrb32->Receive.RingSize;
|
|
|
|
Rrb.Receive.Ring = (TUN_RING *)Rrb32->Receive.Ring;
|
|
|
|
Rrb.Receive.TailMoved = (HANDLE)Rrb32->Receive.TailMoved;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
2019-07-08 11:01:39 +02:00
|
|
|
goto cleanupResetOwner;
|
2020-05-03 09:07:32 +02:00
|
|
|
}
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb.Send.RingSize);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (Status = STATUS_INVALID_PARAMETER,
|
|
|
|
(Ctx->Device.Send.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Send.Capacity > TUN_MAX_RING_CAPACITY ||
|
2020-05-03 09:07:32 +02:00
|
|
|
!IS_POW2(Ctx->Device.Send.Capacity) || !Rrb.Send.TailMoved || !Rrb.Send.Ring))
|
2019-07-08 11:01:39 +02:00
|
|
|
goto cleanupResetOwner;
|
2019-07-05 08:19:56 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
if (!NT_SUCCESS(
|
|
|
|
Status = ObReferenceObjectByHandle(
|
2020-05-03 09:07:32 +02:00
|
|
|
Rrb.Send.TailMoved,
|
2019-07-18 19:43:40 +02:00
|
|
|
/* We will not wait on send ring tail moved event. */
|
|
|
|
EVENT_MODIFY_STATE,
|
2019-07-08 11:01:39 +02:00
|
|
|
*ExEventObjectType,
|
|
|
|
UserMode,
|
|
|
|
&Ctx->Device.Send.TailMoved,
|
|
|
|
NULL)))
|
|
|
|
goto cleanupResetOwner;
|
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb.Send.Ring, Rrb.Send.RingSize, FALSE, FALSE, NULL);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Mdl)
|
|
|
|
goto cleanupSendTailMoved;
|
|
|
|
try
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
MmProbeAndLockPages(Ctx->Device.Send.Mdl, UserMode, IoWriteAccess);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupSendMdl; }
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
Ctx->Device.Send.Ring =
|
|
|
|
MmGetSystemAddressForMdlSafe(Ctx->Device.Send.Mdl, NormalPagePriority | MdlMappingNoExecute);
|
|
|
|
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Ring)
|
|
|
|
goto cleanupSendUnlockPages;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
Ctx->Device.Send.RingTail = ReadULongAcquire(&Ctx->Device.Send.Ring->Tail);
|
2019-07-17 11:53:25 +02:00
|
|
|
if (Status = STATUS_INVALID_PARAMETER, Ctx->Device.Send.RingTail >= Ctx->Device.Send.Capacity)
|
|
|
|
goto cleanupSendUnlockPages;
|
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb.Receive.RingSize);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (Status = STATUS_INVALID_PARAMETER,
|
|
|
|
(Ctx->Device.Receive.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Receive.Capacity > TUN_MAX_RING_CAPACITY ||
|
2020-05-03 09:07:32 +02:00
|
|
|
!IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb.Receive.TailMoved || !Rrb.Receive.Ring))
|
2019-07-08 11:01:39 +02:00
|
|
|
goto cleanupSendUnlockPages;
|
2019-03-22 13:47:17 +01:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
if (!NT_SUCCESS(
|
|
|
|
Status = ObReferenceObjectByHandle(
|
2020-05-03 09:07:32 +02:00
|
|
|
Rrb.Receive.TailMoved,
|
2019-07-18 19:43:40 +02:00
|
|
|
/* We need to clear receive ring TailMoved event on transition to non-alertable state. */
|
|
|
|
SYNCHRONIZE | EVENT_MODIFY_STATE,
|
2019-07-08 11:01:39 +02:00
|
|
|
*ExEventObjectType,
|
|
|
|
UserMode,
|
|
|
|
&Ctx->Device.Receive.TailMoved,
|
|
|
|
NULL)))
|
|
|
|
goto cleanupSendUnlockPages;
|
|
|
|
|
2020-05-03 09:07:32 +02:00
|
|
|
Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb.Receive.Ring, Rrb.Receive.RingSize, FALSE, FALSE, NULL);
|
2019-07-08 11:01:39 +02:00
|
|
|
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Mdl)
|
|
|
|
goto cleanupReceiveTailMoved;
|
|
|
|
try
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
MmProbeAndLockPages(Ctx->Device.Receive.Mdl, UserMode, IoWriteAccess);
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupReceiveMdl; }
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
Ctx->Device.Receive.Ring =
|
|
|
|
MmGetSystemAddressForMdlSafe(Ctx->Device.Receive.Mdl, NormalPagePriority | MdlMappingNoExecute);
|
|
|
|
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Ring)
|
|
|
|
goto cleanupReceiveUnlockPages;
|
2019-06-12 20:00:36 +02:00
|
|
|
|
2019-07-17 14:40:19 +02:00
|
|
|
KeClearEvent(&Ctx->Device.Disconnected);
|
2019-06-12 20:00:36 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
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;
|
2019-06-12 20:00:36 +02:00
|
|
|
|
2019-10-06 11:38:44 +02:00
|
|
|
Ctx->Device.OwningProcessId = PsGetCurrentProcessId();
|
|
|
|
InitializeListHead(&Ctx->Device.Entry);
|
|
|
|
ExAcquireResourceExclusiveLite(&TunDispatchDeviceListLock, TRUE);
|
|
|
|
InsertTailList(&TunDispatchDeviceList, &Ctx->Device.Entry);
|
|
|
|
ExReleaseResourceLite(&TunDispatchDeviceListLock);
|
|
|
|
|
|
|
|
ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
|
2019-07-08 11:01:39 +02:00
|
|
|
TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateConnected);
|
|
|
|
return STATUS_SUCCESS;
|
2019-06-12 20:00:36 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
cleanupFlagsConnected:
|
2019-07-17 14:40:19 +02:00
|
|
|
KeSetEvent(&Ctx->Device.Disconnected, IO_NO_INCREMENT, FALSE);
|
2019-07-08 11:01:39 +02:00
|
|
|
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:
|
2019-10-06 11:38:44 +02:00
|
|
|
Ctx->Device.OwningFileObject = NULL;
|
|
|
|
cleanupMutex:
|
|
|
|
ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
|
2019-06-29 13:34:15 +02:00
|
|
|
return Status;
|
2019-06-12 20:00:36 +02:00
|
|
|
}
|
|
|
|
|
2019-10-06 11:38:44 +02:00
|
|
|
#define TUN_FORCE_UNREGISTRATION ((FILE_OBJECT *)-1)
|
2019-07-08 11:01:39 +02:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-07-18 12:25:37 +02:00
|
|
|
TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
|
2019-06-26 20:34:08 +02:00
|
|
|
{
|
2019-10-06 11:38:44 +02:00
|
|
|
if (!Owner)
|
2019-07-08 11:01:39 +02:00
|
|
|
return;
|
2019-10-06 11:38:44 +02:00
|
|
|
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);
|
2019-07-08 11:01:39 +02:00
|
|
|
|
2019-07-17 14:40:19 +02:00
|
|
|
TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
|
|
|
|
|
|
|
|
KeSetEvent(&Ctx->Device.Disconnected, IO_NO_INCREMENT, FALSE);
|
2019-06-27 11:59:22 +02:00
|
|
|
ExReleaseSpinLockExclusive(
|
|
|
|
&Ctx->TransitionLock,
|
2019-07-17 14:40:19 +02:00
|
|
|
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
|
2019-07-08 11:01:39 +02:00
|
|
|
|
|
|
|
PKTHREAD ThreadObject;
|
|
|
|
if (NT_SUCCESS(
|
|
|
|
ObReferenceObjectByHandle(Ctx->Device.Receive.Thread, SYNCHRONIZE, NULL, KernelMode, &ThreadObject, NULL)))
|
2019-06-26 20:34:08 +02:00
|
|
|
{
|
2019-07-08 11:01:39 +02:00
|
|
|
KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL);
|
|
|
|
ObDereferenceObject(ThreadObject);
|
2019-06-26 20:34:08 +02:00
|
|
|
}
|
2019-07-08 11:01:39 +02:00
|
|
|
ZwClose(Ctx->Device.Receive.Thread);
|
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteULongRelease(&Ctx->Device.Send.Ring->Tail, MAXULONG);
|
2019-07-08 11:01:39 +02:00
|
|
|
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);
|
2019-10-06 11:38:44 +02:00
|
|
|
|
|
|
|
ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
|
2019-06-26 20:34:08 +02:00
|
|
|
}
|
|
|
|
|
2019-07-23 08:37:10 +02:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
2020-10-30 14:21:13 +01:00
|
|
|
static BOOLEAN
|
2019-07-23 08:37:10 +02:00
|
|
|
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;
|
2020-10-30 14:21:13 +01:00
|
|
|
BOOLEAN DidClose = FALSE;
|
2019-07-23 08:37:10 +02:00
|
|
|
|
|
|
|
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)
|
2020-10-30 14:21:13 +01:00
|
|
|
return FALSE;
|
2019-07-23 08:37:10 +02:00
|
|
|
}
|
|
|
|
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);
|
2020-10-30 14:21:13 +01:00
|
|
|
DidClose = TRUE;
|
2019-07-23 08:37:10 +02:00
|
|
|
}
|
|
|
|
KeUnstackDetachProcess(&ApcState);
|
|
|
|
ObfDereferenceObject(Process);
|
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (HandleTable)
|
|
|
|
ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
|
2020-10-30 14:21:13 +01:00
|
|
|
return DidClose;
|
2019-07-23 08:37:10 +02:00
|
|
|
}
|
|
|
|
|
2019-07-18 19:43:40 +02:00
|
|
|
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;
|
2020-04-25 01:43:27 +02:00
|
|
|
*RtlSubAuthoritySid(&LocalSystem, 0) = SECURITY_LOCAL_SYSTEM_RID;
|
2019-07-18 19:43:40 +02:00
|
|
|
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)
|
2019-07-19 08:56:15 +02:00
|
|
|
return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status;
|
2019-07-18 19:43:40 +02:00
|
|
|
TunDispatchSecurityDescriptor = ExAllocatePoolWithTag(NonPagedPoolNx, RequiredBytes, TUN_MEMORY_TAG);
|
|
|
|
if (!TunDispatchSecurityDescriptor)
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, TunDispatchSecurityDescriptor, &RequiredBytes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2020-10-30 17:03:20 +01:00
|
|
|
{
|
|
|
|
ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
|
2019-07-18 19:43:40 +02:00
|
|
|
return Status;
|
2020-10-30 17:03:20 +01:00
|
|
|
}
|
2019-07-18 19:43:40 +02:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-10-06 11:38:44 +02:00
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
2019-07-18 12:25:37 +02:00
|
|
|
_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
|
2019-07-18 13:28:25 +02:00
|
|
|
static DRIVER_DISPATCH_PAGED TunDispatchDeviceControl;
|
2019-03-27 09:00:19 +01:00
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NTSTATUS
|
2019-07-18 12:25:37 +02:00
|
|
|
TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
2019-03-27 09:00:19 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
|
2019-07-23 08:37:10 +02:00
|
|
|
if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS &&
|
|
|
|
Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_FORCE_CLOSE_HANDLES)
|
2019-07-18 12:25:37 +02:00
|
|
|
return NdisDispatchDeviceControl(DeviceObject, Irp);
|
2019-07-18 19:43:40 +02:00
|
|
|
|
|
|
|
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;
|
2019-07-23 08:37:10 +02:00
|
|
|
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
|
|
|
|
{
|
|
|
|
case TUN_IOCTL_REGISTER_RINGS: {
|
2019-07-31 16:10:37 +02:00
|
|
|
KeEnterCriticalRegion();
|
2019-07-23 08:37:10 +02:00
|
|
|
ExAcquireResourceSharedLite(&TunDispatchCtxGuard, TRUE);
|
2019-07-18 12:25:37 +02:00
|
|
|
#pragma warning(suppress : 28175)
|
2019-07-23 08:37:10 +02:00
|
|
|
TUN_CTX *Ctx = DeviceObject->Reserved;
|
|
|
|
Status = NDIS_STATUS_ADAPTER_NOT_READY;
|
|
|
|
if (Ctx)
|
|
|
|
Status = TunRegisterBuffers(Ctx, Irp);
|
|
|
|
ExReleaseResourceLite(&TunDispatchCtxGuard);
|
2019-07-31 16:10:37 +02:00
|
|
|
KeLeaveCriticalRegion();
|
2019-07-23 08:37:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TUN_IOCTL_FORCE_CLOSE_HANDLES:
|
2020-10-30 14:21:13 +01:00
|
|
|
Status = TunForceHandlesClosed(Stack->FileObject->DeviceObject) ? STATUS_SUCCESS : STATUS_NOTHING_TO_TERMINATE;
|
2019-07-23 08:37:10 +02:00
|
|
|
break;
|
|
|
|
}
|
2019-07-18 19:43:40 +02:00
|
|
|
cleanup:
|
2019-06-29 13:34:15 +02:00
|
|
|
Irp->IoStatus.Status = Status;
|
2019-07-18 12:25:37 +02:00
|
|
|
Irp->IoStatus.Information = 0;
|
2019-06-26 14:52:38 +02:00
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
2019-06-29 13:34:15 +02:00
|
|
|
return Status;
|
2019-03-27 09:00:19 +01:00
|
|
|
}
|
|
|
|
|
2019-07-18 12:25:37 +02:00
|
|
|
_Dispatch_type_(IRP_MJ_CLOSE)
|
2019-07-18 13:28:25 +02:00
|
|
|
static DRIVER_DISPATCH_PAGED TunDispatchClose;
|
2019-07-18 12:25:37 +02:00
|
|
|
_Use_decl_annotations_
|
|
|
|
static NTSTATUS
|
|
|
|
TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
|
|
|
{
|
2019-07-31 16:10:37 +02:00
|
|
|
KeEnterCriticalRegion();
|
2019-07-18 19:43:40 +02:00
|
|
|
ExAcquireResourceSharedLite(&TunDispatchCtxGuard, TRUE);
|
2019-07-18 12:25:37 +02:00
|
|
|
#pragma warning(suppress : 28175)
|
|
|
|
TUN_CTX *Ctx = DeviceObject->Reserved;
|
|
|
|
if (Ctx)
|
|
|
|
TunUnregisterBuffers(Ctx, IoGetCurrentIrpStackLocation(Irp)->FileObject);
|
2019-07-18 19:43:40 +02:00
|
|
|
ExReleaseResourceLite(&TunDispatchCtxGuard);
|
2019-07-31 16:10:37 +02:00
|
|
|
KeLeaveCriticalRegion();
|
2019-07-18 12:25:37 +02:00
|
|
|
return NdisDispatchClose(DeviceObject, Irp);
|
|
|
|
}
|
|
|
|
|
2019-03-08 22:33:15 +01:00
|
|
|
static MINIPORT_RESTART TunRestart;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteRelease(&Ctx->Running, TRUE);
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
static MINIPORT_PAUSE TunPause;
|
2019-03-08 22:33:15 +01:00
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
WriteRelease(&Ctx->Running, FALSE);
|
2019-06-27 11:59:22 +02:00
|
|
|
ExReleaseSpinLockExclusive(
|
2019-06-29 13:34:15 +02:00
|
|
|
&Ctx->TransitionLock,
|
|
|
|
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-31 21:53:20 +02:00
|
|
|
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
|
2019-07-18 13:45:30 +02:00
|
|
|
|
2019-07-08 11:01:39 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static MINIPORT_DEVICE_PNP_EVENT_NOTIFY TunDevicePnPEventNotify;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunDevicePnPEventNotify(NDIS_HANDLE MiniportAdapterContext, PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static MINIPORT_INITIALIZE TunInitializeEx;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunInitializeEx(
|
|
|
|
NDIS_HANDLE MiniportAdapterHandle,
|
|
|
|
NDIS_HANDLE MiniportDriverContext,
|
|
|
|
PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
NDIS_STATUS Status;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
if (!MiniportAdapterHandle)
|
|
|
|
return NDIS_STATUS_FAILURE;
|
2019-07-18 13:28:25 +02:00
|
|
|
|
|
|
|
/* Leaking memory 'Ctx'. Note: 'Ctx' is freed in TunHaltEx or on failure. */
|
|
|
|
#pragma warning(suppress : 6014)
|
2019-07-18 12:25:37 +02:00
|
|
|
TUN_CTX *Ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*Ctx), TUN_MEMORY_TAG);
|
|
|
|
if (!Ctx)
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_FAILURE;
|
2019-07-18 12:25:37 +02:00
|
|
|
NdisZeroMemory(Ctx, sizeof(*Ctx));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-18 12:25:37 +02:00
|
|
|
Ctx->MiniportAdapterHandle = MiniportAdapterHandle;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-18 12:25:37 +02:00
|
|
|
NdisMGetDeviceProperty(MiniportAdapterHandle, NULL, &Ctx->FunctionalDeviceObject, NULL, NULL, NULL);
|
2019-07-31 13:51:35 +02:00
|
|
|
if (Status = NDIS_STATUS_FAILURE, !Ctx->FunctionalDeviceObject)
|
|
|
|
goto cleanupFreeCtx;
|
2019-07-31 17:26:29 +02:00
|
|
|
#pragma warning(suppress : 28175)
|
|
|
|
ASSERT(!Ctx->FunctionalDeviceObject->Reserved);
|
2019-06-27 11:46:33 +02:00
|
|
|
/* 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. */
|
2019-06-26 14:52:38 +02:00
|
|
|
#pragma warning(suppress : 28175)
|
2019-07-18 12:25:37 +02:00
|
|
|
Ctx->FunctionalDeviceObject->Reserved = Ctx;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
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 =
|
2019-06-26 14:52:38 +02:00
|
|
|
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;
|
2019-07-17 14:40:19 +02:00
|
|
|
KeInitializeEvent(&Ctx->Device.Disconnected, NotificationEvent, TRUE);
|
2019-07-08 11:01:39 +02:00
|
|
|
KeInitializeSpinLock(&Ctx->Device.Send.Lock);
|
2019-07-18 13:45:30 +02:00
|
|
|
KeInitializeSpinLock(&Ctx->Device.Receive.Lock);
|
2019-07-31 21:53:20 +02:00
|
|
|
KeInitializeEvent(&Ctx->Device.Receive.ActiveNbls.Empty, NotificationEvent, TRUE);
|
2019-10-06 11:38:44 +02:00
|
|
|
ExInitializeResourceLite(&Ctx->Device.RegistrationLock);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
NET_BUFFER_LIST_POOL_PARAMETERS NblPoolParameters = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT,
|
|
|
|
.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
|
|
|
|
.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1 },
|
2019-06-26 14:52:38 +02:00
|
|
|
.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT,
|
|
|
|
.fAllocateNetBuffer = TRUE,
|
2019-07-03 12:43:55 +02:00
|
|
|
.PoolTag = TUN_MEMORY_TAG
|
2019-06-26 18:59:02 +02:00
|
|
|
};
|
2019-07-18 13:28:25 +02:00
|
|
|
/* Leaking memory 'Ctx->NblPool'. Note: 'Ctx->NblPool' is freed in TunHaltEx or on failure. */
|
2019-07-05 13:23:29 +02:00
|
|
|
#pragma warning(suppress : 6014)
|
|
|
|
Ctx->NblPool = NdisAllocateNetBufferListPool(MiniportAdapterHandle, &NblPoolParameters);
|
|
|
|
if (Status = NDIS_STATUS_FAILURE, !Ctx->NblPool)
|
2019-07-18 12:25:37 +02:00
|
|
|
goto cleanupFreeCtx;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES AdapterRegistrationAttributes = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.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 },
|
2019-06-26 14:52:38 +02:00
|
|
|
.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND | NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK,
|
|
|
|
.InterfaceType = NdisInterfaceInternal,
|
2019-06-29 13:34:15 +02:00
|
|
|
.MiniportAdapterContext = Ctx
|
2019-06-26 18:59:02 +02:00
|
|
|
};
|
2019-07-04 23:50:00 +02:00
|
|
|
if (Status = NDIS_STATUS_FAILURE,
|
|
|
|
!NT_SUCCESS(NdisMSetMiniportAttributes(
|
|
|
|
MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterRegistrationAttributes)))
|
2019-07-05 10:38:52 +02:00
|
|
|
goto cleanupFreeNblPool;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-06-29 13:34:15 +02:00
|
|
|
NDIS_PM_CAPABILITIES PmCapabilities = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.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 },
|
2019-06-26 14:52:38 +02:00
|
|
|
.MinMagicPacketWakeUp = NdisDeviceStateUnspecified,
|
|
|
|
.MinPatternWakeUp = NdisDeviceStateUnspecified,
|
2019-06-26 18:59:02 +02:00
|
|
|
.MinLinkChangeWakeUp = NdisDeviceStateUnspecified
|
|
|
|
};
|
2019-06-29 13:34:15 +02:00
|
|
|
static NDIS_OID SupportedOids[] = { OID_GEN_MAXIMUM_TOTAL_SIZE,
|
2019-06-26 18:59:02 +02:00
|
|
|
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 };
|
2019-06-29 13:34:15 +02:00
|
|
|
NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES AdapterGeneralAttributes = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.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 },
|
2019-06-26 14:52:38 +02:00
|
|
|
.MediaType = NdisMediumIP,
|
|
|
|
.PhysicalMediumType = NdisPhysicalMediumUnspecified,
|
2019-07-08 11:01:39 +02:00
|
|
|
.MtuSize = TUN_MAX_IP_PACKET_SIZE,
|
2019-06-26 14:52:38 +02:00
|
|
|
.MaxXmitLinkSpeed = TUN_LINK_SPEED,
|
|
|
|
.MaxRcvLinkSpeed = TUN_LINK_SPEED,
|
|
|
|
.RcvLinkSpeed = TUN_LINK_SPEED,
|
|
|
|
.XmitLinkSpeed = TUN_LINK_SPEED,
|
|
|
|
.MediaConnectState = MediaConnectStateDisconnected,
|
2019-07-08 11:01:39 +02:00
|
|
|
.LookaheadSize = TUN_MAX_IP_PACKET_SIZE,
|
2019-06-26 14:52:38 +02:00
|
|
|
.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,
|
2019-06-29 13:34:15 +02:00
|
|
|
.SupportedStatistics = Ctx->Statistics.SupportedStatistics,
|
2019-06-26 14:52:38 +02:00
|
|
|
.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,
|
2019-06-29 13:34:15 +02:00
|
|
|
.SupportedOidList = SupportedOids,
|
|
|
|
.SupportedOidListLength = sizeof(SupportedOids),
|
|
|
|
.PowerManagementCapabilitiesEx = &PmCapabilities
|
2019-06-26 18:59:02 +02:00
|
|
|
};
|
2019-07-04 23:50:00 +02:00
|
|
|
if (Status = NDIS_STATUS_FAILURE,
|
|
|
|
!NT_SUCCESS(NdisMSetMiniportAttributes(
|
|
|
|
MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneralAttributes)))
|
2019-07-05 10:38:52 +02:00
|
|
|
goto cleanupFreeNblPool;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
/* A miniport driver can call NdisMIndicateStatusEx after setting its
|
|
|
|
* registration attributes even if the driver is still in the context
|
2019-06-26 19:37:29 +02:00
|
|
|
* of the MiniportInitializeEx function. */
|
2019-07-08 11:01:39 +02:00
|
|
|
TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-07-05 10:38:52 +02:00
|
|
|
cleanupFreeNblPool:
|
2019-07-05 13:23:29 +02:00
|
|
|
NdisFreeNetBufferListPool(Ctx->NblPool);
|
2019-07-18 12:25:37 +02:00
|
|
|
cleanupFreeCtx:
|
|
|
|
ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG);
|
2019-06-29 13:34:15 +02:00
|
|
|
return Status;
|
2019-06-17 04:05:45 +02:00
|
|
|
}
|
|
|
|
|
2019-03-08 22:33:15 +01:00
|
|
|
static MINIPORT_HALT TunHaltEx;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-29 13:34:15 +02:00
|
|
|
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-10-06 11:38:44 +02:00
|
|
|
TunUnregisterBuffers(Ctx, TUN_FORCE_UNREGISTRATION);
|
|
|
|
|
2019-06-27 11:59:22 +02:00
|
|
|
ExReleaseSpinLockExclusive(
|
2019-06-29 13:34:15 +02:00
|
|
|
&Ctx->TransitionLock,
|
|
|
|
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
|
2019-07-05 13:23:29 +02:00
|
|
|
NdisFreeNetBufferListPool(Ctx->NblPool);
|
2019-04-10 13:42:16 +02:00
|
|
|
|
2020-04-25 01:47:45 +02:00
|
|
|
#pragma warning(suppress : 6387)
|
|
|
|
WritePointerNoFence(&Ctx->MiniportAdapterHandle, NULL);
|
|
|
|
#pragma warning(suppress : 6387 28175)
|
|
|
|
WritePointerNoFence(&Ctx->FunctionalDeviceObject->Reserved, NULL);
|
2019-07-31 16:10:37 +02:00
|
|
|
KeEnterCriticalRegion();
|
2019-07-18 19:43:40 +02:00
|
|
|
ExAcquireResourceExclusiveLite(&TunDispatchCtxGuard, TRUE); /* Ensure above change is visible to all readers. */
|
|
|
|
ExReleaseResourceLite(&TunDispatchCtxGuard);
|
2019-07-31 16:10:37 +02:00
|
|
|
KeLeaveCriticalRegion();
|
2019-10-06 11:38:44 +02:00
|
|
|
ExDeleteResourceLite(&Ctx->Device.RegistrationLock);
|
2019-07-18 12:25:37 +02:00
|
|
|
ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG);
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
static MINIPORT_SHUTDOWN TunShutdownEx;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunShutdownEx(NDIS_HANDLE MiniportAdapterContext, NDIS_SHUTDOWN_ACTION ShutdownAction)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-04-05 11:04:13 +02:00
|
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
|
|
_Must_inspect_result_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
2019-06-26 19:37:29 +02:00
|
|
|
TunOidQueryWrite(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_ ULONG Value)
|
2019-04-05 11:04:13 +02:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
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);
|
2019-06-26 19:37:29 +02:00
|
|
|
*(ULONG *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = Value;
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-04-05 11:04:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
|
|
_Must_inspect_result_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
2019-06-26 19:37:29 +02:00
|
|
|
TunOidQueryWrite32or64(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_ ULONG64 Value)
|
2019-04-05 11:04:13 +02:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
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);
|
2019-06-26 19:37:29 +02:00
|
|
|
*(ULONG *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (ULONG)(Value & 0xffffffff);
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG64);
|
2019-06-26 19:37:29 +02:00
|
|
|
*(ULONG64 *)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer = Value;
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-04-05 11:04:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
|
|
_Must_inspect_result_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
2019-07-05 15:38:35 +02:00
|
|
|
TunOidQueryWriteBuf(_Inout_ NDIS_OID_REQUEST *OidRequest, _In_bytecount_(Size) const void *Buf, _In_ ULONG Size)
|
2019-04-05 11:04:13 +02:00
|
|
|
{
|
2019-06-26 19:37:29 +02:00
|
|
|
if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < Size)
|
2019-06-26 14:52:38 +02:00
|
|
|
{
|
2019-06-26 19:37:29 +02:00
|
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = Size;
|
2019-06-26 14:52:38 +02:00
|
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
|
|
|
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
|
|
}
|
|
|
|
|
2019-06-26 19:37:29 +02:00
|
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = OidRequest->DATA.QUERY_INFORMATION.BytesWritten = Size;
|
|
|
|
NdisMoveMemory(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, Buf, Size);
|
2019-06-26 14:52:38 +02:00
|
|
|
return NDIS_STATUS_SUCCESS;
|
2019-04-05 11:04:13 +02:00
|
|
|
}
|
|
|
|
|
2019-03-08 22:33:15 +01:00
|
|
|
_IRQL_requires_max_(APC_LEVEL)
|
2019-03-28 11:21:51 +01:00
|
|
|
_Must_inspect_result_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
2019-07-08 11:09:09 +02:00
|
|
|
TunOidQuery(_Inout_ TUN_CTX *Ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
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:
|
2019-07-08 11:01:39 +02:00
|
|
|
return TunOidQueryWrite(OidRequest, TUN_MAX_IP_PACKET_SIZE);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
2019-07-08 11:01:39 +02:00
|
|
|
return TunOidQueryWrite(OidRequest, TUN_MAX_RING_CAPACITY);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
2019-07-08 11:01:39 +02:00
|
|
|
return TunOidQueryWrite(OidRequest, TUN_MAX_RING_CAPACITY);
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_VENDOR_ID:
|
2019-07-29 12:39:47 +02:00
|
|
|
return TunOidQueryWrite(OidRequest, HTONL(TUN_VENDOR_ID));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
2019-07-05 15:38:35 +02:00
|
|
|
return TunOidQueryWriteBuf(OidRequest, TUN_VENDOR_NAME, (ULONG)sizeof(TUN_VENDOR_NAME));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
|
|
|
return TunOidQueryWrite(OidRequest, (WINTUN_VERSION_MAJ << 16) | WINTUN_VERSION_MIN);
|
|
|
|
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
|
|
return TunOidQueryWrite32or64(
|
|
|
|
OidRequest,
|
2020-04-25 01:47:45 +02:00
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) +
|
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) +
|
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_RCV_OK:
|
|
|
|
return TunOidQueryWrite32or64(
|
|
|
|
OidRequest,
|
2020-04-25 01:47:45 +02:00
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) +
|
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) +
|
|
|
|
ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_STATISTICS:
|
2019-07-08 11:09:09 +02:00
|
|
|
return TunOidQueryWriteBuf(OidRequest, &Ctx->Statistics, (ULONG)sizeof(Ctx->Statistics));
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
case OID_GEN_INTERRUPT_MODERATION: {
|
2019-07-05 15:38:35 +02:00
|
|
|
static const NDIS_INTERRUPT_MODERATION_PARAMETERS InterruptParameters = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.Header = { .Type = NDIS_OBJECT_TYPE_DEFAULT,
|
|
|
|
.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1,
|
|
|
|
.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1 },
|
|
|
|
.InterruptModeration = NdisInterruptModerationNotSupported
|
|
|
|
};
|
2019-07-05 15:38:35 +02:00
|
|
|
return TunOidQueryWriteBuf(OidRequest, &InterruptParameters, (ULONG)sizeof(InterruptParameters));
|
2019-06-26 14:52:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
2019-07-08 11:09:09 +02:00
|
|
|
TunOidSet(_Inout_ TUN_CTX *Ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
|
2019-06-07 12:23:44 +02:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
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;
|
2019-06-07 12:23:44 +02:00
|
|
|
}
|
|
|
|
|
2019-03-08 22:33:15 +01:00
|
|
|
static MINIPORT_OID_REQUEST TunOidRequest;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
switch (OidRequest->RequestType)
|
|
|
|
{
|
|
|
|
case NdisRequestQueryInformation:
|
|
|
|
case NdisRequestQueryStatistics:
|
|
|
|
return TunOidQuery(MiniportAdapterContext, OidRequest);
|
|
|
|
|
|
|
|
case NdisRequestSetInformation:
|
|
|
|
return TunOidSet(MiniportAdapterContext, OidRequest);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NDIS_STATUS_INVALID_OID;
|
|
|
|
}
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
static MINIPORT_CANCEL_OID_REQUEST TunCancelOidRequest;
|
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunCancelOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
2019-06-07 12:23:44 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-03-08 22:33:15 +01:00
|
|
|
static MINIPORT_DIRECT_OID_REQUEST TunDirectOidRequest;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
switch (OidRequest->RequestType)
|
|
|
|
{
|
|
|
|
case NdisRequestQueryInformation:
|
|
|
|
case NdisRequestQueryStatistics:
|
|
|
|
case NdisRequestSetInformation:
|
|
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NDIS_STATUS_INVALID_OID;
|
|
|
|
}
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
static MINIPORT_CANCEL_DIRECT_OID_REQUEST TunCancelDirectOidRequest;
|
2019-03-08 22:33:15 +01:00
|
|
|
_Use_decl_annotations_
|
2019-07-18 19:43:40 +02:00
|
|
|
static VOID
|
2019-06-26 14:52:38 +02:00
|
|
|
TunCancelDirectOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-06-07 12:23:44 +02:00
|
|
|
}
|
2019-03-08 22:33:15 +01:00
|
|
|
|
2019-06-21 11:43:17 +02:00
|
|
|
static MINIPORT_SYNCHRONOUS_OID_REQUEST TunSynchronousOidRequest;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static NDIS_STATUS
|
|
|
|
TunSynchronousOidRequest(NDIS_HANDLE MiniportAdapterContext, PNDIS_OID_REQUEST OidRequest)
|
2019-06-21 11:43:17 +02:00
|
|
|
{
|
2019-06-26 14:52:38 +02:00
|
|
|
switch (OidRequest->RequestType)
|
|
|
|
{
|
|
|
|
case NdisRequestQueryInformation:
|
|
|
|
case NdisRequestQueryStatistics:
|
|
|
|
case NdisRequestSetInformation:
|
|
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NDIS_STATUS_INVALID_OID;
|
|
|
|
}
|
2019-06-21 11:43:17 +02:00
|
|
|
}
|
|
|
|
|
2019-06-07 12:23:44 +02:00
|
|
|
static MINIPORT_UNLOAD TunUnload;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
static VOID
|
|
|
|
TunUnload(PDRIVER_OBJECT DriverObject)
|
2019-06-07 12:23:44 +02:00
|
|
|
{
|
2019-10-06 11:38:44 +02:00
|
|
|
PsSetCreateProcessNotifyRoutine(TunProcessNotification, TRUE);
|
2019-06-26 14:52:38 +02:00
|
|
|
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
|
2019-07-18 19:43:40 +02:00
|
|
|
ExDeleteResourceLite(&TunDispatchCtxGuard);
|
2019-10-06 11:38:44 +02:00
|
|
|
ExDeleteResourceLite(&TunDispatchDeviceListLock);
|
2019-07-18 19:43:40 +02:00
|
|
|
ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DRIVER_INITIALIZE DriverEntry;
|
|
|
|
_Use_decl_annotations_
|
2019-06-26 14:52:38 +02:00
|
|
|
NTSTATUS
|
|
|
|
DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
|
2019-03-08 22:33:15 +01:00
|
|
|
{
|
2019-07-08 11:09:09 +02:00
|
|
|
NTSTATUS Status;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-18 19:43:40 +02:00
|
|
|
if (!NT_SUCCESS(Status = TunInitializeDispatchSecurityDescriptor()))
|
|
|
|
return Status;
|
|
|
|
|
2019-06-26 14:52:38 +02:00
|
|
|
NdisVersion = NdisGetVersion();
|
|
|
|
if (NdisVersion < NDIS_MINIPORT_VERSION_MIN)
|
|
|
|
return NDIS_STATUS_UNSUPPORTED_REVISION;
|
|
|
|
if (NdisVersion > NDIS_MINIPORT_VERSION_MAX)
|
|
|
|
NdisVersion = NDIS_MINIPORT_VERSION_MAX;
|
|
|
|
|
2019-07-18 19:43:40 +02:00
|
|
|
ExInitializeResourceLite(&TunDispatchCtxGuard);
|
2019-10-06 11:38:44 +02:00
|
|
|
ExInitializeResourceLite(&TunDispatchDeviceListLock);
|
2019-07-18 12:25:37 +02:00
|
|
|
|
2019-06-26 14:52:38 +02:00
|
|
|
NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniport = {
|
2019-06-26 18:59:02 +02:00
|
|
|
.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 },
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
.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,
|
2019-06-26 18:59:02 +02:00
|
|
|
.SynchronousOidRequestHandler = TunSynchronousOidRequest
|
|
|
|
};
|
2019-10-06 11:38:44 +02:00
|
|
|
|
|
|
|
Status = PsSetCreateProcessNotifyRoutine(TunProcessNotification, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto cleanupResources;
|
|
|
|
|
2019-07-08 11:09:09 +02:00
|
|
|
Status = NdisMRegisterMiniportDriver(DriverObject, RegistryPath, NULL, &miniport, &NdisMiniportDriverHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2019-10-06 11:38:44 +02:00
|
|
|
goto cleanupNotifier;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
2019-07-18 12:25:37 +02:00
|
|
|
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;
|
2019-06-26 14:52:38 +02:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2019-10-06 11:38:44 +02:00
|
|
|
|
|
|
|
cleanupNotifier:
|
|
|
|
PsSetCreateProcessNotifyRoutine(TunProcessNotification, TRUE);
|
|
|
|
cleanupResources:
|
|
|
|
ExDeleteResourceLite(&TunDispatchCtxGuard);
|
|
|
|
ExDeleteResourceLite(&TunDispatchDeviceListLock);
|
|
|
|
ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
|
|
|
|
return Status;
|
2019-03-08 22:33:15 +01:00
|
|
|
}
|