aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2021-04-10 15:33:01 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2021-04-13 15:56:04 -0600
commit564a883e23fff00140c10271f08b37dc649d57c8 (patch)
tree7b7ce433ed469541e68489cd9429b00f04e370b0 /api
parentversion: bump (diff)
downloadwintun-564a883e23fff00140c10271f08b37dc649d57c8.tar.xz
wintun-564a883e23fff00140c10271f08b37dc649d57c8.zip
Allow optional padding before and after layer 3 packets
To avoid additional packet memory allocation and copy when sending or receiving packets, this commit introduces additional available space before and after layer 3 IPv4 or IPv6 packet in the Wintun rings. Wintun will ignore data in those areas. Requested-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'api')
-rw-r--r--api/exports.def1
-rw-r--r--api/session.c72
-rw-r--r--api/wintun.h28
3 files changed, 82 insertions, 19 deletions
diff --git a/api/exports.def b/api/exports.def
index 3539ad8..b69117f 100644
--- a/api/exports.def
+++ b/api/exports.def
@@ -18,3 +18,4 @@ EXPORTS
WintunSetAdapterName
WintunSetLogger
WintunStartSession
+ WintunStartSessionWithPadding
diff --git a/api/session.c b/api/session.c
index ef65214..797850a 100644
--- a/api/session.c
+++ b/api/session.c
@@ -11,13 +11,17 @@
#include <Windows.h>
#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */
+#pragma warning(disable : 4201) /* nonstandard extension used: nameless struct/union */
#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)))
-#define TUN_MAX_PACKET_SIZE TUN_ALIGN(sizeof(TUN_PACKET) + WINTUN_MAX_IP_PACKET_SIZE)
-#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
-#define TUN_RING_SIZE(Capacity) (sizeof(TUN_RING) + (Capacity) + (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
+#define TUN_MAX_PACKET_SIZE(LeadPadding, TrailPadding) \
+ TUN_ALIGN(sizeof(TUN_PACKET) + (LeadPadding) + WINTUN_MAX_IP_PACKET_SIZE + (TrailPadding))
+#define TUN_RING_CAPACITY(Size, LeadPadding, TrailPadding) \
+ ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE(LeadPadding, TrailPadding) - TUN_ALIGNMENT))
+#define TUN_RING_SIZE(Capacity, LeadPadding, TrailPadding) \
+ (sizeof(TUN_RING) + (Capacity) + (TUN_MAX_PACKET_SIZE(LeadPadding, TrailPadding) - TUN_ALIGNMENT))
#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))
#define LOCK_SPIN_COUNT 0x10000
#define TUN_PACKET_RELEASE ((DWORD)0x80000000)
@@ -43,8 +47,18 @@ typedef struct _TUN_REGISTER_RINGS
struct
{
ULONG RingSize;
- TUN_RING *Ring;
- HANDLE TailMoved;
+ ULONG LeadPadding;
+ ULONG TrailPadding;
+ union
+ {
+ TUN_RING *Ring;
+ ULONG64 RingAddress;
+ };
+ union
+ {
+ HANDLE TailMoved;
+ ULONG64 TailMovedHandle;
+ };
} Send, Receive;
} TUN_REGISTER_RINGS;
@@ -69,8 +83,11 @@ typedef struct _TUN_SESSION
HANDLE Handle;
} TUN_SESSION;
-_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
- WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
+_Return_type_success_(return != NULL) TUN_SESSION *WINAPI WintunStartSessionWithPadding(
+ _In_ const WINTUN_ADAPTER *Adapter,
+ _In_ DWORD Capacity,
+ _In_ DWORD LeadPadding,
+ _In_ DWORD TrailPadding)
{
DWORD LastError;
TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION));
@@ -79,7 +96,7 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
LastError = GetLastError();
goto out;
}
- const ULONG RingSize = TUN_RING_SIZE(Capacity);
+ const ULONG RingSize = TUN_RING_SIZE(Capacity, LeadPadding, TrailPadding);
BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!AllocatedRegion)
{
@@ -92,6 +109,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
goto cleanupAllocatedRegion;
}
Session->Descriptor.Send.RingSize = RingSize;
+ Session->Descriptor.Send.LeadPadding = LeadPadding;
+ Session->Descriptor.Send.TrailPadding = TrailPadding;
Session->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
Session->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!Session->Descriptor.Send.TailMoved)
@@ -101,6 +120,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
}
Session->Descriptor.Receive.RingSize = RingSize;
+ Session->Descriptor.Receive.LeadPadding = LeadPadding;
+ Session->Descriptor.Receive.TrailPadding = TrailPadding;
Session->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
Session->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!Session->Descriptor.Receive.TailMoved)
@@ -151,6 +172,12 @@ out:
return NULL;
}
+_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
+ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
+{
+ return WintunStartSessionWithPadding(Adapter, Capacity, 0, 0);
+}
+
void WINAPI
WintunEndSession(_In_ TUN_SESSION *Session)
{
@@ -203,14 +230,16 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI
LastError = ERROR_INVALID_DATA;
goto cleanup;
}
- const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
+ const ULONG AlignedPacketSize = TUN_ALIGN(
+ sizeof(TUN_PACKET) + Session->Descriptor.Send.LeadPadding + BuffPacket->Size +
+ Session->Descriptor.Send.TrailPadding);
if (AlignedPacketSize > BuffContent)
{
LastError = ERROR_INVALID_DATA;
goto cleanup;
}
*PacketSize = BuffPacket->Size;
- BYTE *Packet = BuffPacket->Data;
+ BYTE *Packet = BuffPacket->Data + Session->Descriptor.Send.LeadPadding;
Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
Session->Send.PacketsToRelease++;
LeaveCriticalSection(&Session->Send.Lock);
@@ -225,14 +254,17 @@ void WINAPI
WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
{
EnterCriticalSection(&Session->Send.Lock);
- TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
+ TUN_PACKET *ReleasedBuffPacket =
+ (TUN_PACKET *)(Packet - Session->Descriptor.Send.LeadPadding - offsetof(TUN_PACKET, Data));
ReleasedBuffPacket->Size |= TUN_PACKET_RELEASE;
while (Session->Send.PacketsToRelease)
{
const TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.HeadRelease];
if ((BuffPacket->Size & TUN_PACKET_RELEASE) == 0)
break;
- const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + (BuffPacket->Size & ~TUN_PACKET_RELEASE));
+ const ULONG AlignedPacketSize = TUN_ALIGN(
+ sizeof(TUN_PACKET) + Session->Descriptor.Send.LeadPadding + (BuffPacket->Size & ~TUN_PACKET_RELEASE) +
+ Session->Descriptor.Send.TrailPadding);
Session->Send.HeadRelease = TUN_RING_WRAP(Session->Send.HeadRelease + AlignedPacketSize, Session->Capacity);
Session->Send.PacketsToRelease--;
}
@@ -250,7 +282,9 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
LastError = ERROR_HANDLE_EOF;
goto cleanup;
}
- const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
+ const ULONG AlignedPacketSize = TUN_ALIGN(
+ sizeof(TUN_PACKET) + Session->Descriptor.Receive.LeadPadding + PacketSize +
+ Session->Descriptor.Receive.TrailPadding);
const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head);
if (BuffHead >= Session->Capacity)
{
@@ -265,7 +299,7 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
}
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
- BYTE *Packet = BuffPacket->Data;
+ BYTE *Packet = BuffPacket->Data + Session->Descriptor.Receive.LeadPadding;
Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
Session->Receive.PacketsToRelease++;
LeaveCriticalSection(&Session->Receive.Lock);
@@ -280,7 +314,8 @@ void WINAPI
WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
{
EnterCriticalSection(&Session->Receive.Lock);
- TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
+ TUN_PACKET *ReleasedBuffPacket =
+ (TUN_PACKET *)(Packet - Session->Descriptor.Receive.LeadPadding - offsetof(TUN_PACKET, Data));
ReleasedBuffPacket->Size &= ~TUN_PACKET_RELEASE;
while (Session->Receive.PacketsToRelease)
{
@@ -288,12 +323,15 @@ WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
(TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.TailRelease];
if (BuffPacket->Size & TUN_PACKET_RELEASE)
break;
- const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
+ const ULONG AlignedPacketSize = TUN_ALIGN(
+ sizeof(TUN_PACKET) + Session->Descriptor.Receive.LeadPadding + BuffPacket->Size +
+ Session->Descriptor.Receive.TrailPadding);
Session->Receive.TailRelease =
TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
Session->Receive.PacketsToRelease--;
}
- if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) {
+ if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
+ {
WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
SetEvent(Session->Descriptor.Receive.TailMoved);
diff --git a/api/wintun.h b/api/wintun.h
index 2b03d33..b90ba82 100644
--- a/api/wintun.h
+++ b/api/wintun.h
@@ -63,7 +63,6 @@ typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINT
typedef _Return_type_success_(return != NULL)
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name);
-
/**
* Deletes a Wintun adapter.
*
@@ -220,7 +219,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg
typedef void *WINTUN_SESSION_HANDLE;
/**
- * Starts Wintun session.
+ * Starts Wintun session. Use WintunStartSessionWithPadding() when packet leading and/or trailing space is required.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
*
@@ -234,6 +233,27 @@ typedef _Return_type_success_(return != NULL)
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
/**
+ * Starts Wintun session with specific packet padding.
+ *
+ * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
+ *
+ * @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
+ * Must be a power of two.
+ *
+ * @param LeadPadding Amount of extra space before packet data
+ *
+ * @param TrailPadding Amount of extra space after packet data
+ *
+ * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
+ * NULL. To get extended error information, call GetLastError.
+ */
+typedef _Return_type_success_(return != NULL) WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_WITH_PADDING_FUNC)(
+ _In_ WINTUN_ADAPTER_HANDLE Adapter,
+ _In_ DWORD Capacity,
+ _In_ DWORD LeadPadding,
+ _In_ DWORD TrailPadding);
+
+/**
* Ends Wintun session.
*
* @param Session Wintun session handle obtained with WintunStartSession
@@ -271,6 +291,8 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
* ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
* ERROR_INVALID_DATA Wintun buffer is corrupt
+ * When non-zero padding is used, requested leading amount of space is available before this pointer and
+ * trailing amount of space after this pointer+PacketSize. The driver will ignore padding data.
*/
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *(
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
@@ -298,6 +320,8 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN
* following:
* ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
+ * When non-zero padding is used, requested leading amount of space is available before this pointer and
+ * trailing amount of space after this pointer+PacketSize. The driver will ignore padding data.
*/
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *(
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);