aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2021-04-12 13:08:42 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2021-04-13 15:56:04 -0600
commit47b16dc884992d9c100bc0161d4ca6776a3cd507 (patch)
treed190ac907cc18785575f078ab8229862550d9cc6
parentAllow optional padding before and after layer 3 packets (diff)
downloadwintun-47b16dc884992d9c100bc0161d4ca6776a3cd507.tar.xz
wintun-47b16dc884992d9c100bc0161d4ca6776a3cd507.zip
Allow packet over-allocation on sendsr/api-improvements
Should client desire to prepare packets for Wintun inside the ring memory (e.g. to reduce memory copying), the final sending packet size is not always known at the WintunAllocateSendPacket() time. This commit modifies Wintun to calculate the packet size on delivery to NDIS. The packet size is derived from IPv4/IPv6 packet header. Signed-off-by: Simon Rozman <simon@rozman.si>
-rw-r--r--README.md2
-rw-r--r--api/wintun.h4
-rw-r--r--driver/wintun.c14
3 files changed, 13 insertions, 7 deletions
diff --git a/README.md b/README.md
index af15235..1650266 100644
--- a/README.md
+++ b/README.md
@@ -392,7 +392,7 @@ Allocates memory for a packet to send. After the memory is filled with packet da
**Parameters**
- *Session*: Wintun session handle obtained with WintunStartSession
-- *PacketSize*: Exact packet size. Must be less or equal to WINTUN\_MAX\_IP\_PACKET\_SIZE.
+- *PacketSize*: Upper estimate of packet size. Must be less or equal to WINTUN\_MAX\_IP\_PACKET\_SIZE. The exact size of the packet is determined from layer 3 IPv4 or IPv6 packet header on WintunSendPacket. IPv6 Jumbograms are not supported.
**Returns**
diff --git a/api/wintun.h b/api/wintun.h
index b90ba82..b2395be 100644
--- a/api/wintun.h
+++ b/api/wintun.h
@@ -313,7 +313,9 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN
*
* @param Session Wintun session handle obtained with WintunStartSession
*
- * @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
+ * @param PacketSize Upper estimate of packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE. The exact
+ * size of the packet is determined from layer 3 IPv4 or IPv6 packet header on WintunSendPacket.
+ * IPv6 Jumbograms are not supported.
*
* @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
* the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
diff --git a/driver/wintun.c b/driver/wintun.c
index 4224642..b9a3bb8 100644
--- a/driver/wintun.c
+++ b/driver/wintun.c
@@ -532,15 +532,19 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
if (AlignedPacketSize > RingContent)
break;
+ ULONG Layer3PacketSize;
ULONG NblFlags;
USHORT NblProto;
const UCHAR *PacketData = Packet->Data + Ctx->Device.Receive.LeadPadding;
- if (PacketSize >= 20 && PacketData[0] >> 4 == 4)
+ if (PacketSize >= 20 && PacketData[0] >> 4 == 4 &&
+ (Layer3PacketSize = RtlUshortByteSwap(*(USHORT *)&PacketData[2])) >= 20 && Layer3PacketSize <= PacketSize)
{
NblFlags = NDIS_NBL_FLAGS_IS_IPV4;
NblProto = HTONS(NDIS_ETH_TYPE_IPV4);
}
- else if (PacketSize >= 40 && PacketData[0] >> 4 == 6)
+ else if (
+ PacketSize >= 40 && PacketData[0] >> 4 == 6 &&
+ (Layer3PacketSize = 40ul + RtlUshortByteSwap(*(USHORT *)&PacketData[4])) <= PacketSize)
{
NblFlags = NDIS_NBL_FLAGS_IS_IPV6;
NblProto = HTONS(NDIS_ETH_TYPE_IPV6);
@@ -549,15 +553,15 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
break;
RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
- MDL *Mdl = IoAllocateMdl(NULL, PacketSize, FALSE, FALSE, NULL);
+ MDL *Mdl = IoAllocateMdl(NULL, Layer3PacketSize, FALSE, FALSE, NULL);
if (!Mdl)
goto skipNbl;
IoBuildPartialMdl(
Ctx->Device.Receive.Mdl,
Mdl,
(UCHAR *)MmGetMdlVirtualAddress(Ctx->Device.Receive.Mdl) + (ULONG)(PacketData - (UCHAR *)Ring),
- PacketSize);
- NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, 0, 0, Mdl, 0, PacketSize);
+ Layer3PacketSize);
+ NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, 0, 0, Mdl, 0, Layer3PacketSize);
if (!Nbl)
goto cleanupMdl;
Nbl->SourceHandle = Ctx->MiniportAdapterHandle;