[NDIS]
authorCameron Gutman <aicommander@gmail.com>
Fri, 2 Dec 2011 01:56:10 +0000 (01:56 +0000)
committerCameron Gutman <aicommander@gmail.com>
Fri, 2 Dec 2011 01:56:10 +0000 (01:56 +0000)
- Implement NdisReturnPackets and do proper reference tracking of packets sent to ProtocolReceivePacket
- Plug a massive memory leak that resulted in leaking every packet descriptor that any deserialized miniport indicated to TCP/IP

svn path=/trunk/; revision=54559

reactos/drivers/network/ndis/ndis/50stubs.c
reactos/drivers/network/ndis/ndis/miniport.c

index e7f95cf..9771cbc 100644 (file)
@@ -487,25 +487,6 @@ NdisIMInitializeDeviceInstanceEx(
 }
 
 
-/*
- * @unimplemented
- */
-VOID
-EXPORT
-NdisReturnPackets(
-    IN  PNDIS_PACKET    *PacketsToReturn,
-    IN  UINT            NumberOfPackets)
-/*
- * FUNCTION: Releases ownership of one or more packets
- * ARGUMENTS:
- *     PacketsToReturn = Pointer to an array of pointers to packet descriptors
- *     NumberOfPackets = Number of pointers in descriptor pointer array
- */
-{
-    UNIMPLEMENTED
-}
-
-
 /*
  * @unimplemented
  */
index 4b487f5..20159b5 100644 (file)
@@ -245,7 +245,41 @@ MiniIndicateData(
   NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
-\f
+/*
+ * @implemented
+ */
+VOID
+EXPORT
+NdisReturnPackets(
+    IN  PNDIS_PACKET    *PacketsToReturn,
+    IN  UINT            NumberOfPackets)
+/*
+ * FUNCTION: Releases ownership of one or more packets
+ * ARGUMENTS:
+ *     PacketsToReturn = Pointer to an array of pointers to packet descriptors
+ *     NumberOfPackets = Number of pointers in descriptor pointer array
+ */
+{
+    UINT i;
+    PLOGICAL_ADAPTER Adapter;
+
+    NDIS_DbgPrint(MID_TRACE, ("Returning %d packets\n", NumberOfPackets));
+
+    for (i = 0; i < NumberOfPackets; i++)
+    {
+        PacketsToReturn[i]->WrapperReserved[0]--;
+        if (PacketsToReturn[i]->WrapperReserved[0] == 0)
+        {
+            Adapter = (PVOID)(ULONG_PTR)PacketsToReturn[i]->Reserved[1];
+
+            NDIS_DbgPrint(MAX_TRACE, ("Freeing packet %d (adapter = 0x%p)\n", i, Adapter));
+
+            Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ReturnPacketHandler(
+                  Adapter->NdisMiniportBlock.MiniportAdapterContext,
+                  PacketsToReturn[i]);
+        }
+    }
+}\f
 VOID NTAPI
 MiniIndicateReceivePacket(
     IN  NDIS_HANDLE    MiniportAdapterHandle,
@@ -260,87 +294,139 @@ MiniIndicateReceivePacket(
  *
  */
 {
-  PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
-  PLIST_ENTRY CurrentEntry;
-  PADAPTER_BINDING AdapterBinding;
-  KIRQL OldIrql;
-  UINT i;
-
-  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-
-  CurrentEntry = Adapter->ProtocolListHead.Flink;
-
-  while (CurrentEntry != &Adapter->ProtocolListHead)
-  {
-      AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
+    PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
+    PLIST_ENTRY CurrentEntry;
+    PADAPTER_BINDING AdapterBinding;
+    KIRQL OldIrql;
+    UINT i;
 
-      for (i = 0; i < NumberOfPackets; i++)
-      {
-           if (AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler &&
-               NDIS_GET_PACKET_STATUS(PacketArray[i]) != NDIS_STATUS_RESOURCES)
-           {
-              (*AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler)(
-               AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-               PacketArray[i]);
-           }
-           else
-           {
-              UINT FirstBufferLength, TotalBufferLength, LookAheadSize, HeaderSize;
-              PNDIS_BUFFER NdisBuffer;
-              PVOID NdisBufferVA, LookAheadBuffer;
-              NDIS_STATUS NdisStatus;
+    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
 
+    CurrentEntry = Adapter->ProtocolListHead.Flink;
 
-              NdisGetFirstBufferFromPacket(PacketArray[i],
-                                           &NdisBuffer,
-                                           &NdisBufferVA,
-                                           &FirstBufferLength,
-                                           &TotalBufferLength);
+    while (CurrentEntry != &Adapter->ProtocolListHead)
+    {
+        AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
 
-              HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
+        for (i = 0; i < NumberOfPackets; i++)
+        {
+            /* Store the indicating miniport in the packet */
+            PacketArray[i]->Reserved[1] = (ULONG_PTR)Adapter;
 
-              if (Adapter->NdisMiniportBlock.CurrentLookahead < (TotalBufferLength - HeaderSize))
-              {
-                  LookAheadSize = Adapter->NdisMiniportBlock.CurrentLookahead;
-              }
-              else
-              {
-                  LookAheadSize = TotalBufferLength - HeaderSize;
-              }
+            if (AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler &&
+                NDIS_GET_PACKET_STATUS(PacketArray[i]) != NDIS_STATUS_RESOURCES)
+            {
+                NDIS_DbgPrint(MID_TRACE, ("Indicating packet to protocol's ReceivePacket handler\n"));
+                PacketArray[i]->WrapperReserved[0] += (*AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler)(
+                                                       AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+                                                       PacketArray[i]);
+                NDIS_DbgPrint(MID_TRACE, ("Protocol is holding %d references to the packet\n", PacketArray[i]->WrapperReserved[0]));
+            }
+            else
+            {
+                UINT FirstBufferLength, TotalBufferLength, LookAheadSize, HeaderSize;
+                PNDIS_BUFFER NdisBuffer;
+                PVOID NdisBufferVA, LookAheadBuffer;
+
+                NdisGetFirstBufferFromPacket(PacketArray[i],
+                                             &NdisBuffer,
+                                             &NdisBufferVA,
+                                             &FirstBufferLength,
+                                             &TotalBufferLength);
+                
+                HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
 
+                if (Adapter->NdisMiniportBlock.CurrentLookahead < (TotalBufferLength - HeaderSize))
+                {
+                    LookAheadSize = Adapter->NdisMiniportBlock.CurrentLookahead;
+                }
+                else
+                {
+                    LookAheadSize = TotalBufferLength - HeaderSize;
+                }
 
-              LookAheadBuffer = ExAllocatePool(NonPagedPool, LookAheadSize);
-              if (!LookAheadBuffer)
-              {
-                  NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
-                  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-                  return;
-              }
+                LookAheadBuffer = ExAllocatePool(NonPagedPool, LookAheadSize);
+                if (!LookAheadBuffer)
+                {
+                    NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
+                    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+                    return;
+                }
+                
+                CopyBufferChainToBuffer(LookAheadBuffer,
+                                        NdisBuffer,
+                                        HeaderSize,
+                                        LookAheadSize);
+                
+                NDIS_DbgPrint(MID_TRACE, ("Indicating packet to protocol's legacy Receive handler\n"));
+                (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
+                     AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+                     AdapterBinding->NdisOpenBlock.MacHandle,
+                     NdisBufferVA,
+                     HeaderSize,
+                     LookAheadBuffer,
+                     LookAheadSize,
+                     TotalBufferLength - HeaderSize);
+                
+                ExFreePool(LookAheadBuffer);
+            }
+        }
 
-              CopyBufferChainToBuffer(LookAheadBuffer,
-                                      NdisBuffer,
-                                      HeaderSize,
-                                      LookAheadSize);
+        CurrentEntry = CurrentEntry->Flink;
+    }
 
-              NdisStatus = (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
-                            AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-                            AdapterBinding->NdisOpenBlock.MacHandle,
-                            NdisBufferVA,
-                            HeaderSize,
-                            LookAheadBuffer,
-                            LookAheadSize,
-                            TotalBufferLength - HeaderSize);
+    /* Loop the packet array to get everything
+     * set up for return the packets to the miniport */
+    for (i = 0; i < NumberOfPackets; i++)
+    {
+        /* First, check the initial packet status */
+        if (NDIS_GET_PACKET_STATUS(PacketArray[i]) == NDIS_STATUS_RESOURCES)
+        {
+            /* The miniport driver gets it back immediately so nothing to do here */
+            NDIS_DbgPrint(MID_TRACE, ("Miniport needs the packet back immediately\n"));
+            continue;
+        }
 
-              NDIS_SET_PACKET_STATUS(PacketArray[i], NdisStatus);
+        /* Different behavior depending on whether it's serialized or not */
+        if (Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
+        {
+            /* We need to check the reference count */
+            if (PacketArray[i]->WrapperReserved[0] == 0)
+            {
+                /* NOTE: Unlike serialized miniports, this is REQUIRED to be called for each
+                 * packet received that can be reused immediately, it is not implied! */
+                Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ReturnPacketHandler(
+                      Adapter->NdisMiniportBlock.MiniportAdapterContext,
+                      PacketArray[i]);
+                NDIS_DbgPrint(MID_TRACE, ("Packet has been returned to miniport (Deserialized)\n"));
+            }
+            else
+            {
+                /* Packet will be returned by the protocol's call to NdisReturnPackets */
+                NDIS_DbgPrint(MID_TRACE, ("Packet will be returned to miniport later (Deserialized)\n"));
+            }
+        }
+        else
+        {
+            /* Check the reference count */
+            if (PacketArray[i]->WrapperReserved[0] == 0)
+            {
+                /* NDIS_STATUS_SUCCESS means the miniport can have the packet back immediately */
+                NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS);
 
-              ExFreePool(LookAheadBuffer);
-          }
-      }
+                NDIS_DbgPrint(MID_TRACE, ("Packet has been returned to miniport (Serialized)\n"));
+            }
+            else
+            {
+                /* NDIS_STATUS_PENDING means the miniport needs to wait for MiniportReturnPacket */
+                NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_PENDING);
 
-      CurrentEntry = CurrentEntry->Flink;
-  }
+                NDIS_DbgPrint(MID_TRACE, ("Packet will be returned to miniport later (Serialized)\n"));
+            }
+        }
+    }
 
-  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
 }
 
 \f