From 77ed514f6423df1065c4d8679228f7ca951e959f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 2 Dec 2011 01:56:10 +0000 Subject: [PATCH] [NDIS] - 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 | 19 -- reactos/drivers/network/ndis/ndis/miniport.c | 222 +++++++++++++------ 2 files changed, 154 insertions(+), 87 deletions(-) diff --git a/reactos/drivers/network/ndis/ndis/50stubs.c b/reactos/drivers/network/ndis/ndis/50stubs.c index e7f95cfed62..9771cbccb4b 100644 --- a/reactos/drivers/network/ndis/ndis/50stubs.c +++ b/reactos/drivers/network/ndis/ndis/50stubs.c @@ -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 */ diff --git a/reactos/drivers/network/ndis/ndis/miniport.c b/reactos/drivers/network/ndis/ndis/miniport.c index 4b487f5c0a3..20159b52ecd 100644 --- a/reactos/drivers/network/ndis/ndis/miniport.c +++ b/reactos/drivers/network/ndis/ndis/miniport.c @@ -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); }