]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
In Windows TAP driver, refactor DHCP/ARP packet injection code to
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 22 Jun 2009 20:48:35 +0000 (20:48 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 22 Jun 2009 20:48:35 +0000 (20:48 +0000)
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

install-win32/settings.in
tap-win32/constants.h
tap-win32/dhcp.c
tap-win32/prototypes.h
tap-win32/tapdrvr.c
tap-win32/types.h
version.m4

index 742fd317b1cdda25c78d0455f26664a6f5c982e9..cbfe58d23311a5d75d80cc635a8b32cf4a647a23 100644 (file)
 # 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.
index b6a3d566260f4fa2e2fad356c184f9c97c5708fa..fc7855dcd015393b33c73e7e4cb8f602a1b53d1b 100755 (executable)
@@ -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
index 47e299595228cc6a5a0489114e3fa28f22aea3d4..b6b28bb7f32a74d0d1de998aa329dbc3f59247ae 100755 (executable)
@@ -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
        {
index c342ad3b014f9130e5ad419e6d257f2244636fc0..29502d6039bf66657d2a5d376797fe24feaedc9c 100755 (executable)
@@ -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
index cd4d179ef703e211a0f1dbf25bfed2d36090549e..a856734bdc11f47fade04e878015c8f4afec7ca7 100755 (executable)
@@ -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 ();
     }
index d424521392df6cd37313d2658da3a591eff0c8d8..4adee6a6f3992b60fd3d46334c1da9fd6b2393e5 100755 (executable)
@@ -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)
index 370f7eb239e2da80e51a8b4e3ca275fc0142e165..d843c4c06efc4ab72d15e81168d4eb2c0ef5d934 100644 (file)
@@ -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])