summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2009-06-22 20:48:35 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2009-06-22 20:48:35 +0000
commit7ea8261049d8897b46e26f62dec3f6768e0b3f9a (patch)
tree763d0b19f9a1f695b5591b6b4633121a0d30457c
parent7132f9dfba0ca4d9a5f639360dcb009d29fa4782 (diff)
downloadopenvpn-7ea8261049d8897b46e26f62dec3f6768e0b3f9a.tar.gz
openvpn-7ea8261049d8897b46e26f62dec3f6768e0b3f9a.tar.xz
openvpn-7ea8261049d8897b46e26f62dec3f6768e0b3f9a.zip
In Windows TAP driver, refactor DHCP/ARP packet injection code to
use a DPC (deferred procedure call) to defer packet injection until IRQL < DISPATCH_LEVEL, rather than calling NdisMEthIndicateReceive in the context of AdapterTransmit. This is an attempt to reduce kernel stack usage, and prevent EXCEPTION_DOUBLE_FAULT BSODs that have been observed on Vista. Updated TAP driver version number to 9.6. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@4606 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r--install-win32/settings.in12
-rwxr-xr-xtap-win32/constants.h1
-rwxr-xr-xtap-win32/dhcp.c6
-rwxr-xr-xtap-win32/prototypes.h21
-rwxr-xr-xtap-win32/tapdrvr.c125
-rwxr-xr-xtap-win32/types.h15
-rw-r--r--version.m42
7 files changed, 154 insertions, 28 deletions
diff --git a/install-win32/settings.in b/install-win32/settings.in
index 742fd31..cbfe58d 100644
--- a/install-win32/settings.in
+++ b/install-win32/settings.in
@@ -30,20 +30,20 @@
# Optional directory of prebuilt OpenVPN binary components,
# to be used as a source when build-from-scratch prerequisites
# are not met.
-!define GENOUT_PREBUILT "../gen-prebuilt"
+;!define GENOUT_PREBUILT "../gen-prebuilt"
# tapinstall.exe source code.
# Not needed if DRVBINSRC is defined
# (or if using pre-built mode).
-;!define TISRC "../tapinstall"
+!define TISRC "../tapinstall"
# TAP Adapter parameters. Note that PRODUCT_TAP_ID is
# defined in version.m4.
!define PRODUCT_TAP_DEVICE_DESCRIPTION "TAP-Win32 Adapter V9"
!define PRODUCT_TAP_PROVIDER "TAP-Win32 Provider V9"
!define PRODUCT_TAP_MAJOR_VER 9
-!define PRODUCT_TAP_MINOR_VER 5
-!define PRODUCT_TAP_RELDATE "05/13/2009"
+!define PRODUCT_TAP_MINOR_VER 6
+!define PRODUCT_TAP_RELDATE "06/22/2009"
# TAP adapter icon -- visible=0x81 or hidden=0x89
!define PRODUCT_TAP_CHARACTERISTICS 0x81
@@ -53,8 +53,8 @@
# DDK Version.
# DDK distribution is assumed to be in C:\WINDDK\${DDKVER}
-;!define DDKVER 6001.18002
-;!define DDKVER_MAJOR 6001
+!define DDKVER 6001.18002
+!define DDKVER_MAJOR 6001
# Code Signing.
# If undefined, don't sign any files.
diff --git a/tap-win32/constants.h b/tap-win32/constants.h
index b6a3d56..fc7855d 100755
--- a/tap-win32/constants.h
+++ b/tap-win32/constants.h
@@ -51,5 +51,6 @@
#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size
#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace
+#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue
#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions
diff --git a/tap-win32/dhcp.c b/tap-win32/dhcp.c
index 47e2995..b6b28bb 100755
--- a/tap-win32/dhcp.c
+++ b/tap-win32/dhcp.c
@@ -379,9 +379,9 @@ SendDHCPMsg (const TapAdapterPointer a,
DHCPMSG_LEN_FULL (pkt));
// Return DHCP response to kernel
- InjectPacket (a,
- DHCPMSG_BUF (pkt),
- DHCPMSG_LEN_FULL (pkt));
+ InjectPacketDeferred (a,
+ DHCPMSG_BUF (pkt),
+ DHCPMSG_LEN_FULL (pkt));
}
else
{
diff --git a/tap-win32/prototypes.h b/tap-win32/prototypes.h
index c342ad3..29502d6 100755
--- a/tap-win32/prototypes.h
+++ b/tap-win32/prototypes.h
@@ -171,13 +171,32 @@ VOID SetMediaStatus
BOOLEAN state
);
-VOID InjectPacket
+VOID InjectPacketDeferred
(
TapAdapterPointer p_Adapter,
UCHAR *packet,
const unsigned int len
);
+VOID InjectPacketNow
+ (
+ TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len
+ );
+
+// for KDEFERRED_ROUTINE and Static Driver Verifier
+//#include <wdm.h>
+//KDEFERRED_ROUTINE InjectPacketDpc;
+
+VOID InjectPacketDpc
+ (
+ KDPC *Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+ );
+
VOID CheckIfDhcpAndTunMode
(
TapAdapterPointer p_Adapter
diff --git a/tap-win32/tapdrvr.c b/tap-win32/tapdrvr.c
index cd4d179..a856734 100755
--- a/tap-win32/tapdrvr.c
+++ b/tap-win32/tapdrvr.c
@@ -692,6 +692,8 @@ TapDeviceFreeResources (TapExtensionPointer p_Extension)
QueueFree (p_Extension->m_PacketQueue);
if (p_Extension->m_IrpQueue)
QueueFree (p_Extension->m_IrpQueue);
+ if (p_Extension->m_InjectQueue)
+ QueueFree (p_Extension->m_InjectQueue);
if (p_Extension->m_CreatedUnicodeLinkName)
RtlFreeUnicodeString (&p_Extension->m_UnicodeLinkName);
@@ -717,8 +719,14 @@ TapDeviceFreeResources (TapExtensionPointer p_Extension)
if (p_Extension->m_TapName)
MemFree (p_Extension->m_TapName, NAME_BUFFER_SIZE);
+ if (p_Extension->m_InjectDpcInitialized)
+ KeRemoveQueueDpc (&p_Extension->m_InjectDpc);
+
if (p_Extension->m_AllocatedSpinlocks)
- NdisFreeSpinLock (&p_Extension->m_QueueLock);
+ {
+ NdisFreeSpinLock (&p_Extension->m_QueueLock);
+ NdisFreeSpinLock (&p_Extension->m_InjectLock);
+ }
}
//========================================================================
@@ -932,19 +940,28 @@ CreateTapDevice (TapExtensionPointer p_Extension, const char *p_Name)
//========================================================
NdisAllocateSpinLock (&p_Extension->m_QueueLock);
+ NdisAllocateSpinLock (&p_Extension->m_InjectLock);
p_Extension->m_AllocatedSpinlocks = TRUE;
p_Extension->m_PacketQueue = QueueInit (PACKET_QUEUE_SIZE);
p_Extension->m_IrpQueue = QueueInit (IRP_QUEUE_SIZE);
-
+ p_Extension->m_InjectQueue = QueueInit (INJECT_QUEUE_SIZE);
if (!p_Extension->m_PacketQueue
- || !p_Extension->m_IrpQueue)
+ || !p_Extension->m_IrpQueue
+ || !p_Extension->m_InjectQueue)
{
DEBUGP (("[%s] couldn't alloc TAP queues\n", p_Name));
l_Return = NDIS_STATUS_RESOURCES;
goto cleanup;
}
+ //=================================================================
+ // Initialize deferred procedure call for DHCP/ARP packet injection
+ //=================================================================
+
+ KeInitializeDpc (&p_Extension->m_InjectDpc, InjectPacketDpc, NULL);
+ p_Extension->m_InjectDpcInitialized = TRUE;
+
//========================
// Finalize initialization
//========================
@@ -1808,9 +1825,9 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
NULL,
STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
#if PACKET_TRUNCATION_CHECK
- "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
+ "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
#else
- "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
+ "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
#endif
state,
g_LastErrorFilename,
@@ -1831,7 +1848,10 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
(int)IRP_QUEUE_SIZE,
(int)l_Adapter->m_Extension.m_PacketQueue->size,
(int)l_Adapter->m_Extension.m_PacketQueue->max_size,
- (int)PACKET_QUEUE_SIZE
+ (int)PACKET_QUEUE_SIZE,
+ (int)l_Adapter->m_Extension.m_InjectQueue->size,
+ (int)l_Adapter->m_Extension.m_InjectQueue->max_size,
+ (int)INJECT_QUEUE_SIZE
);
p_IRP->IoStatus.Information
@@ -2519,15 +2539,16 @@ CancelIRP (TapExtensionPointer p_Extension,
IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
}
-//====================================
-// Exhaust packet and IRP queues.
-//====================================
+//===========================================
+// Exhaust packet, IRP, and injection queues.
+//===========================================
VOID
FlushQueues (TapExtensionPointer p_Extension)
{
PIRP l_IRP;
TapPacketPointer l_PacketBuffer;
- int n_IRP=0, n_Packet=0;
+ InjectPacketPointer l_InjectBuffer;
+ int n_IRP=0, n_Packet=0, n_Inject=0;
MYASSERT (p_Extension);
MYASSERT (p_Extension->m_TapDevice);
@@ -2560,15 +2581,32 @@ FlushQueues (TapExtensionPointer p_Extension)
break;
}
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_InjectLock);
+ l_InjectBuffer = QueuePop (p_Extension->m_InjectQueue);
+ NdisReleaseSpinLock (&p_Extension->m_InjectLock);
+ if (l_InjectBuffer)
+ {
+ ++n_Inject;
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+ else
+ break;
+ }
+
DEBUGP ((
- "[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d]\n",
+ "[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d] n_Inject=[%d,%d,%d]\n",
p_Extension->m_TapName,
n_IRP,
p_Extension->m_IrpQueue->max_size,
IRP_QUEUE_SIZE,
n_Packet,
p_Extension->m_PacketQueue->max_size,
- PACKET_QUEUE_SIZE
+ PACKET_QUEUE_SIZE,
+ n_Inject,
+ p_Extension->m_InjectQueue->max_size,
+ INJECT_QUEUE_SIZE
));
}
@@ -2667,7 +2705,7 @@ ProcessARP (TapAdapterPointer p_Adapter,
(unsigned char *) arp,
sizeof (ARP_PACKET));
- InjectPacket (p_Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
+ InjectPacketDeferred (p_Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
MemFree (arp, sizeof (ARP_PACKET));
}
@@ -2684,10 +2722,60 @@ ProcessARP (TapAdapterPointer p_Adapter,
// seen as an incoming packet "arriving" on the interface.
//===============================================================
+// Defer packet injection till IRQL < DISPATCH_LEVEL
VOID
-InjectPacket (TapAdapterPointer p_Adapter,
- UCHAR *packet,
- const unsigned int len)
+InjectPacketDeferred (TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len)
+{
+ InjectPacketPointer l_InjectBuffer;
+ PVOID result;
+
+ if (NdisAllocateMemoryWithTag (&l_InjectBuffer,
+ INJECT_PACKET_SIZE (len),
+ 'IPAT') == NDIS_STATUS_SUCCESS)
+ {
+ l_InjectBuffer->m_Size = len;
+ NdisMoveMemory (l_InjectBuffer->m_Data, packet, len);
+ NdisAcquireSpinLock (&p_Adapter->m_Extension.m_InjectLock);
+ result = QueuePush (p_Adapter->m_Extension.m_InjectQueue, l_InjectBuffer);
+ NdisReleaseSpinLock (&p_Adapter->m_Extension.m_InjectLock);
+ if (result)
+ KeInsertQueueDpc (&p_Adapter->m_Extension.m_InjectDpc, p_Adapter, NULL);
+ else
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+}
+
+// Handle the injection of previously deferred packets
+VOID
+InjectPacketDpc(KDPC *Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ InjectPacketPointer l_InjectBuffer;
+ TapAdapterPointer l_Adapter = (TapAdapterPointer)SystemArgument1;
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_InjectLock);
+ l_InjectBuffer = QueuePop (l_Adapter->m_Extension.m_InjectQueue);
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_InjectLock);
+ if (l_InjectBuffer)
+ {
+ InjectPacketNow(l_Adapter, l_InjectBuffer->m_Data, l_InjectBuffer->m_Size);
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+ else
+ break;
+ }
+}
+
+// Do packet injection now
+VOID
+InjectPacketNow (TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len)
{
MYASSERT (len >= ETHERNET_HEADER_SIZE);
@@ -2699,6 +2787,9 @@ InjectPacket (TapAdapterPointer p_Adapter,
// TapDeviceHook/IRP_MJ_WRITE.
//
// The DDK docs imply that this is okay.
+ //
+ // Note that reentrant behavior could only occur if the
+ // non-deferred version of InjectPacket is used.
//------------------------------------------------------------
NdisMEthIndicateReceive
(p_Adapter->m_MiniportAdapterHandle,
@@ -2713,7 +2804,7 @@ InjectPacket (TapAdapterPointer p_Adapter,
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacket\n",
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacketNow\n",
NAME (p_Adapter)));
NOTE_ERROR ();
}
diff --git a/tap-win32/types.h b/tap-win32/types.h
index d424521..4adee6a 100755
--- a/tap-win32/types.h
+++ b/tap-win32/types.h
@@ -86,6 +86,12 @@ typedef struct _TapExtension
// Flags
BOOLEAN m_TapIsRunning;
BOOLEAN m_CalledTapDeviceFreeResources;
+
+ // DPC queue for deferred packet injection
+ BOOLEAN m_InjectDpcInitialized;
+ KDPC m_InjectDpc;
+ NDIS_SPIN_LOCK m_InjectLock;
+ Queue *m_InjectQueue;
}
TapExtension, *TapExtensionPointer;
@@ -99,6 +105,15 @@ typedef struct _TapPacket
}
TapPacket, *TapPacketPointer;
+typedef struct _InjectPacket
+ {
+# define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size))
+# define INJECT_PACKET_FREE(ib) NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0)
+ ULONG m_Size;
+ UCHAR m_Data []; // m_Data must be the last struct member
+ }
+InjectPacket, *InjectPacketPointer;
+
typedef struct _TapAdapter
{
# define NAME(a) ((a)->m_NameAnsi.Buffer)
diff --git a/version.m4 b/version.m4
index 370f7eb..d843c4c 100644
--- a/version.m4
+++ b/version.m4
@@ -1,5 +1,5 @@
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1_rc18])
+define(PRODUCT_VERSION,[2.1_rc18a])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])