- 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
This commit is contained in:
Cameron Gutman 2011-12-02 01:56:10 +00:00
parent f5fda30d65
commit 77ed514f64
2 changed files with 154 additions and 87 deletions

View 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
*/

View file

@ -245,7 +245,41 @@ MiniIndicateData(
NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
}
/*
* @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]);
}
}
}
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;
PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
PLIST_ENTRY CurrentEntry;
PADAPTER_BINDING AdapterBinding;
KIRQL OldIrql;
UINT i;
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
CurrentEntry = Adapter->ProtocolListHead.Flink;
CurrentEntry = Adapter->ProtocolListHead.Flink;
while (CurrentEntry != &Adapter->ProtocolListHead)
{
AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
while (CurrentEntry != &Adapter->ProtocolListHead)
{
AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
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;
for (i = 0; i < NumberOfPackets; i++)
{
/* Store the indicating miniport in the packet */
PacketArray[i]->Reserved[1] = (ULONG_PTR)Adapter;
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);
NdisGetFirstBufferFromPacket(PacketArray[i],
&NdisBuffer,
&NdisBufferVA,
&FirstBufferLength,
&TotalBufferLength);
HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
if (Adapter->NdisMiniportBlock.CurrentLookahead < (TotalBufferLength - HeaderSize))
{
LookAheadSize = Adapter->NdisMiniportBlock.CurrentLookahead;
}
else
{
LookAheadSize = TotalBufferLength - HeaderSize;
}
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;
}
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);
}
}
CurrentEntry = CurrentEntry->Flink;
}
LookAheadBuffer = ExAllocatePool(NonPagedPool, LookAheadSize);
if (!LookAheadBuffer)
{
NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
return;
}
/* 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;
}
CopyBufferChainToBuffer(LookAheadBuffer,
NdisBuffer,
HeaderSize,
LookAheadSize);
/* 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);
NdisStatus = (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
AdapterBinding->NdisOpenBlock.MacHandle,
NdisBufferVA,
HeaderSize,
LookAheadBuffer,
LookAheadSize,
TotalBufferLength - HeaderSize);
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);
NDIS_SET_PACKET_STATUS(PacketArray[i], NdisStatus);
NDIS_DbgPrint(MID_TRACE, ("Packet will be returned to miniport later (Serialized)\n"));
}
}
}
ExFreePool(LookAheadBuffer);
}
}
CurrentEntry = CurrentEntry->Flink;
}
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
}