title: Windows Filtering Platform Network Slowdown Due to Spinlock
body: <p>I am writing a Windows Filtering Platform Kernel Mode Driver, the goal of the driver is to capture all traffic on a particular layer, and communicate this traffic back down to user-mode so that it can be further analyses. The driver never needs to block any traffic, the classifyOut is always set to <code>FWP_ACTION_CONTINUE</code>.</p>
  
  <p>The following code is used in my Classify function to queue up the packets that are received.</p>
  
  <pre><code>classifyOut-&gt;actionType = FWP_ACTION_CONTINUE;
  
  do
  {
      if ((classifyOut-&gt;rights &amp; FWPS_RIGHT_ACTION_WRITE) == 0)
      {
          break;
      }
  
      if (layerData != NULL)
      {
          PNET_BUFFER_LIST netBufferList = (PNET_BUFFER_LIST) layerData;
          PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(netBufferList);
  
          if (packetQueueSize &gt;= 2048)
          {
              ExInterlockedRemoveHeadList(&amp;packetQueue, &amp;packetQueueLock);
              packetQueueSize--;
          }
  
          ULONG netBufferSize = NET_BUFFER_DATA_LENGTH(netBuffer);
          PACKET_ITEM* allocatedPacket = InitalizePacketItem(
              netBuffer,
              netBufferSize
          );
  
          if (allocatedPacket == NULL)
          {
              classifyOut-&gt;actionType = FWP_ACTION_BLOCK;
              classifyOut-&gt;rights &amp;= ~FWPS_RIGHT_ACTION_WRITE;
              break;
          }
  
          ExInterlockedInsertTailList(
              &amp;packetQueue,
              &amp;allocatedPacket-&gt;listEntry,
              &amp;packetQueueLock
          );
          allocatedPacket = NULL;
          packetQueueSize++;
      }
  } while (FALSE);
  </code></pre>
  
  <p>The <code>PACKET_ITEM</code> struct is defined as the following</p>
  
  <pre>
  typedef struct _PACKET_ITEM {
      LIST_ENTRY listEntry;
      PVOID data;
      ULONG dataLen;
  } PACKET_ITEM;
  </pre>
  
  <p>I am using the inverted call model to communicate this packet data from kernel mode to user mode. The following code is used in the kernel driver once it detects the correct IOCTL has been sent.</p>
  
  <pre><code>status = WdfRequestRetrieveOutputBuffer(request, 0, &amp;buffer, &amp;bufferSize);
  if (!NT_SUCCESS(status))
  {
      break;
  }
  
  PLIST_ENTRY listEntry = ExInterlockedRemoveHeadList(&amp;packetQueue, &amp;packetQueueLock);
  if (listEntry == NULL)
  {
      break;
  }
  
  PACKET_ITEM* packetItem = CONTAINING_RECORD(
      listEntry,
      struct _PACKET_ITEM,
      listEntry
  );
  
  RtlCopyMemory(
      buffer,
      packetItem-&gt;data,
      packetItem-&gt;dataLen);
  
  status = STATUS_SUCCESS;
  WdfRequestCompleteWithInformation(
      request,
      status,
      packetItem-&gt;dataLen
  );
  
  FreePacketItem(packetItem);
  </code></pre>
  
  <p>This code seems to slow the network down greatly after a short while, causing timeouts when trying to load websites in a web browser, for example.</p>
  
  <p>I assume this is being caused by the spinlocks and the sheer volume of packets being transferred across the network that are being captured by this driver.</p>
  
  <p>My questions are the following</p>
  
  <ul>
  <li>Is it likely the spinlock is definitely causing my problems here? If so
  
  <ul>
  <li>Is it possible to set the <code>classifyOut-&gt;actionType</code> immediately and return this value before allocating any memory to copy the data into my queue. I assume this would prevent the slow down from happening?</li>
  <li>What else should I be doing differently to prevent this?</li>
  </ul></li>
  <li>If not,
  
  <ul>
  <li>What is causing the issue with the slow down here?</li>
  </ul></li>
  </ul>