From: Peter Schmitz on
Hi,

I'm currently trying to develop a NDIS IM driver, that duplicates every
packet it ought to send/receive, kills the original one - and (after some
short period) sends/receives the duplicate instead.
Therefore, I created a function, that shall duplicate the NDIS_PACKETs, but
which, unfortunately, seems to create some memory leaks (I have no idea
why).

So, here goes some source code:

PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
BOOLEAN tosend)
{
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
PRECV_RSVD RecvRsvd;
PSEND_RSVD SendRsvd;

//tosend == FALSE -> packet is going to be received
if(tosend == FALSE)
{
NdisDprAllocatePacket(&Status, &MyPacket, Adapter->RecvPacketPoolHandle);
RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
RecvRsvd->OriginalPkt = OriginalPacket;
}
else
{
NdisDprAllocatePacket(&Status, &MyPacket, Adapter->SendPacketPoolHandle);
SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
SendRsvd->OriginalPkt = NULL;//marking packet as crafted
}

MyPacket->Private.Head = OriginalPacket->Private.Head;
MyPacket->Private.Tail = OriginalPacket->Private.Tail;

NDIS_SET_ORIGINAL_PACKET(MyPacket,NDIS_GET_ORIGINAL_PACKET(OriginalPacket));

NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(OriginalPacket);

Status = NDIS_GET_PACKET_STATUS(OriginalPacket);

NDIS_SET_PACKET_STATUS(MyPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(MyPacket,
NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
return (MyPacket);
}

Now, I'm not quite satisfied with this function (although it seems to work)
as it seems to me that I don't really copy any packet data...
Additionally, if I mark any packet that shall be received later on with a
NULL pointer at OriginalPkt, MPReturnPackets crashes, if I enter a pointer
to the real original packet, everything works fine.

Anyway, the PtSendComplete handler looks as follows:

VOID
PtSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status
)
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET Pkt;
NDIS_HANDLE PoolHandle;


PSEND_RSVD SendRsvd;


SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
Pkt = SendRsvd->OriginalPkt;

if( Pkt )
{

PoolHandle = NdisGetPoolFromPacket(Packet);
if (PoolHandle != pAdapt->SendPacketPoolHandle)
{
NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status);
}
else
{
NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
NdisDprFreePacket(Packet);
NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
}
}
else
{
//packet was crafted, just free it
NdisDprFreePacket(Packet);
}
}

Any ideas, what could cause the memory leaks? Do you have any comments on
the DuplicatePacket function? Could this code really work as expected
(although it seems to do so)?

There's a second problem: When I additionally start ethereal on the testing
machine, the NdisSend call I make to send the packet fails with
DRIVER_IRQL_NOT_LESS_OR_EQUAL. Any ideas on that?


Greetings,
Peter
From: Maxim S. Shatskih on
IIRC you must also copy the packet's OOB data using some NDIS_xxx macro.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim(a)storagecraft.com
http://www.storagecraft.com

"Peter Schmitz" <PeterSchmitz(a)discussions.microsoft.com> wrote in message
news:B7753EC0-EFA8-462F-876B-E857E9BDFFF8(a)microsoft.com...
> Hi,
>
> I'm currently trying to develop a NDIS IM driver, that duplicates every
> packet it ought to send/receive, kills the original one - and (after some
> short period) sends/receives the duplicate instead.
> Therefore, I created a function, that shall duplicate the NDIS_PACKETs, but
> which, unfortunately, seems to create some memory leaks (I have no idea
> why).
>
> So, here goes some source code:
>
> PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
> BOOLEAN tosend)
> {
> NDIS_STATUS Status;
> PNDIS_PACKET MyPacket;
> PRECV_RSVD RecvRsvd;
> PSEND_RSVD SendRsvd;
>
> //tosend == FALSE -> packet is going to be received
> if(tosend == FALSE)
> {
> NdisDprAllocatePacket(&Status, &MyPacket, Adapter->RecvPacketPoolHandle);
> RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
> RecvRsvd->OriginalPkt = OriginalPacket;
> }
> else
> {
> NdisDprAllocatePacket(&Status, &MyPacket, Adapter->SendPacketPoolHandle);
> SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
> SendRsvd->OriginalPkt = NULL;//marking packet as crafted
> }
>
> MyPacket->Private.Head = OriginalPacket->Private.Head;
> MyPacket->Private.Tail = OriginalPacket->Private.Tail;
>
> NDIS_SET_ORIGINAL_PACKET(MyPacket,NDIS_GET_ORIGINAL_PACKET(OriginalPacket));
>
> NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(OriginalPacket);
>
> Status = NDIS_GET_PACKET_STATUS(OriginalPacket);
>
> NDIS_SET_PACKET_STATUS(MyPacket, Status);
> NDIS_SET_PACKET_HEADER_SIZE(MyPacket,
> NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
> return (MyPacket);
> }
>
> Now, I'm not quite satisfied with this function (although it seems to work)
> as it seems to me that I don't really copy any packet data...
> Additionally, if I mark any packet that shall be received later on with a
> NULL pointer at OriginalPkt, MPReturnPackets crashes, if I enter a pointer
> to the real original packet, everything works fine.
>
> Anyway, the PtSendComplete handler looks as follows:
>
> VOID
> PtSendComplete(
> IN NDIS_HANDLE ProtocolBindingContext,
> IN PNDIS_PACKET Packet,
> IN NDIS_STATUS Status
> )
> {
> PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
> PNDIS_PACKET Pkt;
> NDIS_HANDLE PoolHandle;
>
>
> PSEND_RSVD SendRsvd;
>
>
> SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
> Pkt = SendRsvd->OriginalPkt;
>
> if( Pkt )
> {
>
> PoolHandle = NdisGetPoolFromPacket(Packet);
> if (PoolHandle != pAdapt->SendPacketPoolHandle)
> {
> NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status);
> }
> else
> {
> NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
> NdisDprFreePacket(Packet);
> NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
> }
> }
> else
> {
> //packet was crafted, just free it
> NdisDprFreePacket(Packet);
> }
> }
>
> Any ideas, what could cause the memory leaks? Do you have any comments on
> the DuplicatePacket function? Could this code really work as expected
> (although it seems to do so)?
>
> There's a second problem: When I additionally start ethereal on the testing
> machine, the NdisSend call I make to send the packet fails with
> DRIVER_IRQL_NOT_LESS_OR_EQUAL. Any ideas on that?
>
>
> Greetings,
> Peter


From: Stephan Wolf [MVP] on
Several things to consider here:

- Calling NdisDprAllocatePacket() from any IRQL below DISPATCH_LEVEL is
a programming fault and can cause unpredictable results. So please use
the non-DPR variant NdisAllocatePacket() if you are not 100% sure. Same
is true for the free function.

- Your local packet uses the same NDIS_BUFFER chain as the original
packet. Thus, the lifetime of your local packet cannot be any longer
than that of the original. That is, as soon as you "kill" the original
packet (i.e. return it back to NDIS), your should also "kill" your
local packet.

- NDIS_SET_ORIGINAL_PACKET() sets a reference (back-link) in your local
packet to the "original" packet of the packet you are making a copy of.
(Usually, the packet returned by NDIS_GET_ORIGINAL_PACKET() is just the
same as the one passed to the macro but can be different in some
cases.)
Since you "kill" the original packet, this reference also becomes
invalid. So better set as follows:

NDIS_SET_ORIGINAL_PACKET(MyPacket, MyPacket);

...which IIRC is the default anyway.

- I guess you should set the status of your local packet to
NDIS_STATUS_SUCCESS rather than that of the original packet via
NDIS_SET_PACKET_STATUS().

- Umm, I have difficulties trying to understand your PtSendComplete().
First you get 'Pkt' from 'Packet->ProtocolReserved'. So this means
'Packet' must be one of your own local packets. But if the pool handle
of 'Packet' is not your own - which is is contradictory - you return
this packet to NdisMSendComplete().

Stephan
---
Peter Schmitz wrote:
> Hi,
>
> I'm currently trying to develop a NDIS IM driver, that duplicates every
> packet it ought to send/receive, kills the original one - and (after some
> short period) sends/receives the duplicate instead.
> Therefore, I created a function, that shall duplicate the NDIS_PACKETs, but
> which, unfortunately, seems to create some memory leaks (I have no idea
> why).
>
> So, here goes some source code:
>
> PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
> BOOLEAN tosend)
> {
> NDIS_STATUS Status;
> PNDIS_PACKET MyPacket;
> PRECV_RSVD RecvRsvd;
> PSEND_RSVD SendRsvd;
>
> //tosend == FALSE -> packet is going to be received
> if(tosend == FALSE)
> {
> NdisDprAllocatePacket(&Status, &MyPacket, Adapter->RecvPacketPoolHandle);
> RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
> RecvRsvd->OriginalPkt = OriginalPacket;
> }
> else
> {
> NdisDprAllocatePacket(&Status, &MyPacket, Adapter->SendPacketPoolHandle);
> SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
> SendRsvd->OriginalPkt = NULL;//marking packet as crafted
> }
>
> MyPacket->Private.Head = OriginalPacket->Private.Head;
> MyPacket->Private.Tail = OriginalPacket->Private.Tail;
>
> NDIS_SET_ORIGINAL_PACKET(MyPacket,NDIS_GET_ORIGINAL_PACKET(OriginalPacket));
>
> NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(OriginalPacket);
>
> Status = NDIS_GET_PACKET_STATUS(OriginalPacket);
>
> NDIS_SET_PACKET_STATUS(MyPacket, Status);
> NDIS_SET_PACKET_HEADER_SIZE(MyPacket,
> NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
> return (MyPacket);
> }
>
> Now, I'm not quite satisfied with this function (although it seems to work)
> as it seems to me that I don't really copy any packet data...
> Additionally, if I mark any packet that shall be received later on with a
> NULL pointer at OriginalPkt, MPReturnPackets crashes, if I enter a pointer
> to the real original packet, everything works fine.
>
> Anyway, the PtSendComplete handler looks as follows:
>
> VOID
> PtSendComplete(
> IN NDIS_HANDLE ProtocolBindingContext,
> IN PNDIS_PACKET Packet,
> IN NDIS_STATUS Status
> )
> {
> PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
> PNDIS_PACKET Pkt;
> NDIS_HANDLE PoolHandle;
>
>
> PSEND_RSVD SendRsvd;
>
>
> SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
> Pkt = SendRsvd->OriginalPkt;
>
> if( Pkt )
> {
>
> PoolHandle = NdisGetPoolFromPacket(Packet);
> if (PoolHandle != pAdapt->SendPacketPoolHandle)
> {
> NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status);
> }
> else
> {
> NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
> NdisDprFreePacket(Packet);
> NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
> }
> }
> else
> {
> //packet was crafted, just free it
> NdisDprFreePacket(Packet);
> }
> }
>
> Any ideas, what could cause the memory leaks? Do you have any comments on
> the DuplicatePacket function? Could this code really work as expected
> (although it seems to do so)?
>
> There's a second problem: When I additionally start ethereal on the testing
> machine, the NdisSend call I make to send the packet fails with
> DRIVER_IRQL_NOT_LESS_OR_EQUAL. Any ideas on that?
>
>
> Greetings,
> Peter

From: Peter Schmitz on
Thanks for replying! According to your suggestions I rewrote the function to
create a real independent copy of any NDIS_PACKET:

PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
BOOLEAN tosend)
{
PNDIS_PACKET OurPacket = NULL;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNDIS_BUFFER pNdisBuffer,pOurBuffer;
ULONG PacketLength = 0;
ULONG bytescopied = 0;
PVOID virtualaddr = NULL;
PRECV_RSVD RecvRsvd;
PSEND_RSVD SendRsvd;

if(tosend == FALSE)
{
NdisAllocatePacket(&Status, &OurPacket, Adapter->RecvPacketPoolHandle);
}
else
{
NdisAllocatePacket(&Status,&OurPacket,Adapter->SendPacketPoolHandle);
}
NdisQueryPacket(OriginalPacket, NULL, NULL,&pNdisBuffer,&PacketLength );

NdisAllocateMemoryWithTag(&virtualaddr,PacketLength,'DMSA');

NdisAllocateBuffer(&Status,&pOurBuffer,Adapter->BufferPool,
virtualaddr,PacketLength);

NdisChainBufferAtFront(OurPacket,pOurBuffer);
NdisCopyFromPacketToPacket(OurPacket,0,PacketLength,OriginalPacket,0,
&bytescopied);

OurPacket->Private.Head = OriginalPacket->Private.Head;
OurPacket->Private.Tail = OriginalPacket->Private.Tail;

if(tosend == FALSE)
{
RecvRsvd = (PRECV_RSVD)(OurPacket->MiniportReserved);
RecvRsvd->OriginalPkt = NULL;
}
else
{
SendRsvd = (PSEND_RSVD)(OurPacket->ProtocolReserved);
SendRsvd->OriginalPkt = NULL;
}
NdisSetPacketFlags(OurPacket, NdisGetPacketFlags(OriginalPacket));
NdisFreeMemory(virtualaddr,PacketLength,0);

NDIS_SET_PACKET_STATUS(OurPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(OurPacket,
NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
return OurPacket;
}

Now, the NULL pointer to OriginalPkt in my ProtocolReserved area is
necessary for me to distinguish between real packets - and my own copies (as
I need to kill the buffers etc. for them).
So, I just test Pkt for being NULL in my PtCompleteSend handler, and if so
(my own copy as packet) delete the buffers.

Or...would, as a BAD_POOL_CALLER appears at NdisFreeBuffer saying that the
memory was already freed....but how?

Thanks in advance,

Peter





"Stephan Wolf [MVP]" wrote:

> Several things to consider here:
>
> - Calling NdisDprAllocatePacket() from any IRQL below DISPATCH_LEVEL is
> a programming fault and can cause unpredictable results. So please use
> the non-DPR variant NdisAllocatePacket() if you are not 100% sure. Same
> is true for the free function.
>
> - Your local packet uses the same NDIS_BUFFER chain as the original
> packet. Thus, the lifetime of your local packet cannot be any longer
> than that of the original. That is, as soon as you "kill" the original
> packet (i.e. return it back to NDIS), your should also "kill" your
> local packet.
>
> - NDIS_SET_ORIGINAL_PACKET() sets a reference (back-link) in your local
> packet to the "original" packet of the packet you are making a copy of.
> (Usually, the packet returned by NDIS_GET_ORIGINAL_PACKET() is just the
> same as the one passed to the macro but can be different in some
> cases.)
> Since you "kill" the original packet, this reference also becomes
> invalid. So better set as follows:
>
> NDIS_SET_ORIGINAL_PACKET(MyPacket, MyPacket);
>
> ...which IIRC is the default anyway.
>
> - I guess you should set the status of your local packet to
> NDIS_STATUS_SUCCESS rather than that of the original packet via
> NDIS_SET_PACKET_STATUS().
>
> - Umm, I have difficulties trying to understand your PtSendComplete().
> First you get 'Pkt' from 'Packet->ProtocolReserved'. So this means
> 'Packet' must be one of your own local packets. But if the pool handle
> of 'Packet' is not your own - which is is contradictory - you return
> this packet to NdisMSendComplete().
>
> Stephan
> ---
> Peter Schmitz wrote:
> > Hi,
> >
> > I'm currently trying to develop a NDIS IM driver, that duplicates every
> > packet it ought to send/receive, kills the original one - and (after some
> > short period) sends/receives the duplicate instead.
> > Therefore, I created a function, that shall duplicate the NDIS_PACKETs, but
> > which, unfortunately, seems to create some memory leaks (I have no idea
> > why).
> >
> > So, here goes some source code:
> >
> > PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
> > BOOLEAN tosend)
> > {
> > NDIS_STATUS Status;
> > PNDIS_PACKET MyPacket;
> > PRECV_RSVD RecvRsvd;
> > PSEND_RSVD SendRsvd;
> >
> > //tosend == FALSE -> packet is going to be received
> > if(tosend == FALSE)
> > {
> > NdisDprAllocatePacket(&Status, &MyPacket, Adapter->RecvPacketPoolHandle);
> > RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
> > RecvRsvd->OriginalPkt = OriginalPacket;
> > }
> > else
> > {
> > NdisDprAllocatePacket(&Status, &MyPacket, Adapter->SendPacketPoolHandle);
> > SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
> > SendRsvd->OriginalPkt = NULL;//marking packet as crafted
> > }
> >
> > MyPacket->Private.Head = OriginalPacket->Private.Head;
> > MyPacket->Private.Tail = OriginalPacket->Private.Tail;
> >
> > NDIS_SET_ORIGINAL_PACKET(MyPacket,NDIS_GET_ORIGINAL_PACKET(OriginalPacket));
> >
> > NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(OriginalPacket);
> >
> > Status = NDIS_GET_PACKET_STATUS(OriginalPacket);
> >
> > NDIS_SET_PACKET_STATUS(MyPacket, Status);
> > NDIS_SET_PACKET_HEADER_SIZE(MyPacket,
> > NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
> > return (MyPacket);
> > }
> >
> > Now, I'm not quite satisfied with this function (although it seems to work)
> > as it seems to me that I don't really copy any packet data...
> > Additionally, if I mark any packet that shall be received later on with a
> > NULL pointer at OriginalPkt, MPReturnPackets crashes, if I enter a pointer
> > to the real original packet, everything works fine.
> >
> > Anyway, the PtSendComplete handler looks as follows:
> >
> > VOID
> > PtSendComplete(
> > IN NDIS_HANDLE ProtocolBindingContext,
> > IN PNDIS_PACKET Packet,
> > IN NDIS_STATUS Status
> > )
> > {
> > PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
> > PNDIS_PACKET Pkt;
> > NDIS_HANDLE PoolHandle;
> >
> >
> > PSEND_RSVD SendRsvd;
> >
> >
> > SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
> > Pkt = SendRsvd->OriginalPkt;
> >
> > if( Pkt )
> > {
> >
> > PoolHandle = NdisGetPoolFromPacket(Packet);
> > if (PoolHandle != pAdapt->SendPacketPoolHandle)
> > {
> > NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status);
> > }
> > else
> > {
> > NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
> > NdisDprFreePacket(Packet);
> > NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
> > }
> > }
> > else
> > {
> > //packet was crafted, just free it
> > NdisDprFreePacket(Packet);
> > }
> > }
> >
> > Any ideas, what could cause the memory leaks? Do you have any comments on
> > the DuplicatePacket function? Could this code really work as expected
> > (although it seems to do so)?
> >
> > There's a second problem: When I additionally start ethereal on the testing
> > machine, the NdisSend call I make to send the packet fails with
> > DRIVER_IRQL_NOT_LESS_OR_EQUAL. Any ideas on that?
> >
> >
> > Greetings,
> > Peter
>
>
From: Thomas F. Divine [DDK MVP] on

Peter,

1.) Why do you do this?

OurPacket->Private.Head = OriginalPacket->Private.Head;
OurPacket->Private.Tail = OriginalPacket->Private.Tail;

You no longer have a real "duplicate". In fact, despite the fact that you
have gone to the trouble of allocating your own VM and your own NDIS_BUFFER,
these steps (above) completely overwrite your buffer chain with the buffers
from the original packet. So, if you try to free your own packet descriptor
(NDIS_PACKET) later the buffers that you will try to free will actually be
those from the original packet. That will surely cause problems at some
point.

It is unfortunate that Microsoft exposed the "Private" parts of the
NDIS_PACKET in the NDIS IM driver model. These fields should only be
tinkered with when simply doing a PassThru of a packet with no modification
or duplication.

2.) In your completion routines you are ALWAYS called with YOUR packet. So,
you know that you must free the resources associated with your own packet.

The OriginalPkt field in the Reserved areas is used to keep track of the
original send or receive packet that was passed into your driver in the
first place. Basically, if the field is NULL, then there is no original
packet to deal with. If it is NOT NULL then you must return the original
packet to it's owner. For example, in ProtocolSendComplete you would call
NdisMSendComplete ONLY if OriginalPkt was NOT NULL.

Good luck,

Thomas F. Divine, Windows DDK MVP
http://www.pcausa.com


"Peter Schmitz" <PeterSchmitz(a)discussions.microsoft.com> wrote in message
news:681D17E8-FB64-406C-8D81-421D4C53B9C0(a)microsoft.com...
> Thanks for replying! According to your suggestions I rewrote the function
> to
> create a real independent copy of any NDIS_PACKET:
>
> PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT Adapter,
> BOOLEAN tosend)
> {
> PNDIS_PACKET OurPacket = NULL;
> NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
> PNDIS_BUFFER pNdisBuffer,pOurBuffer;
> ULONG PacketLength = 0;
> ULONG bytescopied = 0;
> PVOID virtualaddr = NULL;
> PRECV_RSVD RecvRsvd;
> PSEND_RSVD SendRsvd;
>
> if(tosend == FALSE)
> {
> NdisAllocatePacket(&Status, &OurPacket, Adapter->RecvPacketPoolHandle);
> }
> else
> {
> NdisAllocatePacket(&Status,&OurPacket,Adapter->SendPacketPoolHandle);
> }
> NdisQueryPacket(OriginalPacket, NULL, NULL,&pNdisBuffer,&PacketLength );
>
> NdisAllocateMemoryWithTag(&virtualaddr,PacketLength,'DMSA');
>
> NdisAllocateBuffer(&Status,&pOurBuffer,Adapter->BufferPool,
> virtualaddr,PacketLength);
>
> NdisChainBufferAtFront(OurPacket,pOurBuffer);
> NdisCopyFromPacketToPacket(OurPacket,0,PacketLength,OriginalPacket,0,
> &bytescopied);
>
> OurPacket->Private.Head = OriginalPacket->Private.Head;
> OurPacket->Private.Tail = OriginalPacket->Private.Tail;
>
> if(tosend == FALSE)
> {
> RecvRsvd = (PRECV_RSVD)(OurPacket->MiniportReserved);
> RecvRsvd->OriginalPkt = NULL;
> }
> else
> {
> SendRsvd = (PSEND_RSVD)(OurPacket->ProtocolReserved);
> SendRsvd->OriginalPkt = NULL;
> }
> NdisSetPacketFlags(OurPacket, NdisGetPacketFlags(OriginalPacket));
> NdisFreeMemory(virtualaddr,PacketLength,0);
>
> NDIS_SET_PACKET_STATUS(OurPacket, Status);
> NDIS_SET_PACKET_HEADER_SIZE(OurPacket,
> NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
> return OurPacket;
> }
>
> Now, the NULL pointer to OriginalPkt in my ProtocolReserved area is
> necessary for me to distinguish between real packets - and my own copies
> (as
> I need to kill the buffers etc. for them).
> So, I just test Pkt for being NULL in my PtCompleteSend handler, and if so
> (my own copy as packet) delete the buffers.
>
> Or...would, as a BAD_POOL_CALLER appears at NdisFreeBuffer saying that the
> memory was already freed....but how?
>
> Thanks in advance,
>
> Peter
>
>
>
>
>
> "Stephan Wolf [MVP]" wrote:
>
>> Several things to consider here:
>>
>> - Calling NdisDprAllocatePacket() from any IRQL below DISPATCH_LEVEL is
>> a programming fault and can cause unpredictable results. So please use
>> the non-DPR variant NdisAllocatePacket() if you are not 100% sure. Same
>> is true for the free function.
>>
>> - Your local packet uses the same NDIS_BUFFER chain as the original
>> packet. Thus, the lifetime of your local packet cannot be any longer
>> than that of the original. That is, as soon as you "kill" the original
>> packet (i.e. return it back to NDIS), your should also "kill" your
>> local packet.
>>
>> - NDIS_SET_ORIGINAL_PACKET() sets a reference (back-link) in your local
>> packet to the "original" packet of the packet you are making a copy of.
>> (Usually, the packet returned by NDIS_GET_ORIGINAL_PACKET() is just the
>> same as the one passed to the macro but can be different in some
>> cases.)
>> Since you "kill" the original packet, this reference also becomes
>> invalid. So better set as follows:
>>
>> NDIS_SET_ORIGINAL_PACKET(MyPacket, MyPacket);
>>
>> ...which IIRC is the default anyway.
>>
>> - I guess you should set the status of your local packet to
>> NDIS_STATUS_SUCCESS rather than that of the original packet via
>> NDIS_SET_PACKET_STATUS().
>>
>> - Umm, I have difficulties trying to understand your PtSendComplete().
>> First you get 'Pkt' from 'Packet->ProtocolReserved'. So this means
>> 'Packet' must be one of your own local packets. But if the pool handle
>> of 'Packet' is not your own - which is is contradictory - you return
>> this packet to NdisMSendComplete().
>>
>> Stephan
>> ---
>> Peter Schmitz wrote:
>> > Hi,
>> >
>> > I'm currently trying to develop a NDIS IM driver, that duplicates every
>> > packet it ought to send/receive, kills the original one - and (after
>> > some
>> > short period) sends/receives the duplicate instead.
>> > Therefore, I created a function, that shall duplicate the NDIS_PACKETs,
>> > but
>> > which, unfortunately, seems to create some memory leaks (I have no idea
>> > why).
>> >
>> > So, here goes some source code:
>> >
>> > PNDIS_PACKET DuplicatePacket(PNDIS_PACKET OriginalPacket,PADAPT
>> > Adapter,
>> > BOOLEAN tosend)
>> > {
>> > NDIS_STATUS Status;
>> > PNDIS_PACKET MyPacket;
>> > PRECV_RSVD RecvRsvd;
>> > PSEND_RSVD SendRsvd;
>> >
>> > //tosend == FALSE -> packet is going to be received
>> > if(tosend == FALSE)
>> > {
>> > NdisDprAllocatePacket(&Status, &MyPacket,
>> > Adapter->RecvPacketPoolHandle);
>> > RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
>> > RecvRsvd->OriginalPkt = OriginalPacket;
>> > }
>> > else
>> > {
>> > NdisDprAllocatePacket(&Status, &MyPacket,
>> > Adapter->SendPacketPoolHandle);
>> > SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
>> > SendRsvd->OriginalPkt = NULL;//marking packet as crafted
>> > }
>> >
>> > MyPacket->Private.Head = OriginalPacket->Private.Head;
>> > MyPacket->Private.Tail = OriginalPacket->Private.Tail;
>> >
>> > NDIS_SET_ORIGINAL_PACKET(MyPacket,NDIS_GET_ORIGINAL_PACKET(OriginalPacket));
>> >
>> > NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(OriginalPacket);
>> >
>> > Status = NDIS_GET_PACKET_STATUS(OriginalPacket);
>> >
>> > NDIS_SET_PACKET_STATUS(MyPacket, Status);
>> > NDIS_SET_PACKET_HEADER_SIZE(MyPacket,
>> > NDIS_GET_PACKET_HEADER_SIZE(OriginalPacket));
>> > return (MyPacket);
>> > }
>> >
>> > Now, I'm not quite satisfied with this function (although it seems to
>> > work)
>> > as it seems to me that I don't really copy any packet data...
>> > Additionally, if I mark any packet that shall be received later on with
>> > a
>> > NULL pointer at OriginalPkt, MPReturnPackets crashes, if I enter a
>> > pointer
>> > to the real original packet, everything works fine.
>> >
>> > Anyway, the PtSendComplete handler looks as follows:
>> >
>> > VOID
>> > PtSendComplete(
>> > IN NDIS_HANDLE ProtocolBindingContext,
>> > IN PNDIS_PACKET Packet,
>> > IN NDIS_STATUS Status
>> > )
>> > {
>> > PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
>> > PNDIS_PACKET Pkt;
>> > NDIS_HANDLE PoolHandle;
>> >
>> >
>> > PSEND_RSVD SendRsvd;
>> >
>> >
>> > SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
>> > Pkt = SendRsvd->OriginalPkt;
>> >
>> > if( Pkt )
>> > {
>> >
>> > PoolHandle = NdisGetPoolFromPacket(Packet);
>> > if (PoolHandle != pAdapt->SendPacketPoolHandle)
>> > {
>> > NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status);
>> > }
>> > else
>> > {
>> > NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
>> > NdisDprFreePacket(Packet);
>> > NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
>> > }
>> > }
>> > else
>> > {
>> > //packet was crafted, just free it
>> > NdisDprFreePacket(Packet);
>> > }
>> > }
>> >
>> > Any ideas, what could cause the memory leaks? Do you have any comments
>> > on
>> > the DuplicatePacket function? Could this code really work as expected
>> > (although it seems to do so)?
>> >
>> > There's a second problem: When I additionally start ethereal on the
>> > testing
>> > machine, the NdisSend call I make to send the packet fails with
>> > DRIVER_IRQL_NOT_LESS_OR_EQUAL. Any ideas on that?
>> >
>> >
>> > Greetings,
>> > Peter
>>
>>