mirror of
https://github.com/reactos/reactos.git
synced 2024-09-20 17:51:53 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
409 lines
11 KiB
C
409 lines
11 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS TCP/IP protocol driver
|
|
* FILE: tcpip/buffer.c
|
|
* PURPOSE: Miscellaneous operations on NDIS_BUFFERs and packets.
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* REVISIONS:
|
|
* CSH 01/08-2000 Created
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
__inline INT SkipToOffset(
|
|
PNDIS_BUFFER Buffer,
|
|
UINT Offset,
|
|
PCHAR *Data,
|
|
PUINT Size)
|
|
/*
|
|
* FUNCTION: Skip Offset bytes into a buffer chain
|
|
* ARGUMENTS:
|
|
* Buffer = Pointer to NDIS buffer
|
|
* Offset = Number of bytes to skip
|
|
* Data = Address of a pointer that on return will contain the
|
|
* address of the offset in the buffer
|
|
* Size = Address of a pointer that on return will contain the
|
|
* size of the destination buffer
|
|
* RETURNS:
|
|
* Offset into buffer, -1 if buffer chain was smaller than Offset bytes
|
|
* NOTES:
|
|
* Buffer may be NULL
|
|
*/
|
|
{
|
|
for (;;) {
|
|
|
|
if (!Buffer)
|
|
return -1;
|
|
|
|
NdisQueryBuffer(Buffer, (PVOID)Data, Size);
|
|
|
|
if (Offset < *Size) {
|
|
*Data = (PCHAR)((ULONG_PTR) *Data + Offset);
|
|
*Size -= Offset;
|
|
break;
|
|
}
|
|
|
|
Offset -= *Size;
|
|
|
|
NdisGetNextBuffer(Buffer, &Buffer);
|
|
}
|
|
|
|
return Offset;
|
|
}
|
|
|
|
|
|
UINT CopyBufferToBufferChain(
|
|
PNDIS_BUFFER DstBuffer,
|
|
UINT DstOffset,
|
|
PCHAR SrcData,
|
|
UINT Length)
|
|
/*
|
|
* FUNCTION: Copies data from a buffer to an NDIS buffer chain
|
|
* ARGUMENTS:
|
|
* DstBuffer = Pointer to destination NDIS buffer
|
|
* DstOffset = Destination start offset
|
|
* SrcData = Pointer to source buffer
|
|
* Length = Number of bytes to copy
|
|
* RETURNS:
|
|
* Number of bytes copied to destination buffer
|
|
* NOTES:
|
|
* The number of bytes copied may be limited by the destination
|
|
* buffer size
|
|
*/
|
|
{
|
|
UINT BytesCopied, BytesToCopy, DstSize;
|
|
PCHAR DstData;
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcData (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));
|
|
|
|
/* Skip DstOffset bytes in the destination buffer chain */
|
|
if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
|
|
return 0;
|
|
|
|
/* Start copying the data */
|
|
BytesCopied = 0;
|
|
for (;;) {
|
|
BytesToCopy = MIN(DstSize, Length);
|
|
|
|
RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
|
|
BytesCopied += BytesToCopy;
|
|
SrcData = (PCHAR)((ULONG_PTR)SrcData + BytesToCopy);
|
|
|
|
Length -= BytesToCopy;
|
|
if (Length == 0)
|
|
break;
|
|
|
|
DstSize -= BytesToCopy;
|
|
if (DstSize == 0) {
|
|
/* No more bytes in desination buffer. Proceed to
|
|
the next buffer in the destination buffer chain */
|
|
NdisGetNextBuffer(DstBuffer, &DstBuffer);
|
|
if (!DstBuffer)
|
|
break;
|
|
|
|
NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
|
|
}
|
|
}
|
|
|
|
return BytesCopied;
|
|
}
|
|
|
|
|
|
UINT CopyBufferChainToBuffer(
|
|
PCHAR DstData,
|
|
PNDIS_BUFFER SrcBuffer,
|
|
UINT SrcOffset,
|
|
UINT Length)
|
|
/*
|
|
* FUNCTION: Copies data from an NDIS buffer chain to a buffer
|
|
* ARGUMENTS:
|
|
* DstData = Pointer to destination buffer
|
|
* SrcBuffer = Pointer to source NDIS buffer
|
|
* SrcOffset = Source start offset
|
|
* Length = Number of bytes to copy
|
|
* RETURNS:
|
|
* Number of bytes copied to destination buffer
|
|
* NOTES:
|
|
* The number of bytes copied may be limited by the source
|
|
* buffer size
|
|
*/
|
|
{
|
|
UINT BytesCopied, BytesToCopy, SrcSize;
|
|
PCHAR SrcData;
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("DstData 0x%X SrcBuffer 0x%X SrcOffset 0x%X Length %d\n",DstData,SrcBuffer, SrcOffset, Length));
|
|
|
|
/* Skip SrcOffset bytes in the source buffer chain */
|
|
if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
|
|
return 0;
|
|
|
|
/* Start copying the data */
|
|
BytesCopied = 0;
|
|
for (;;) {
|
|
BytesToCopy = MIN(SrcSize, Length);
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
|
|
|
|
RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
|
|
BytesCopied += BytesToCopy;
|
|
DstData = (PCHAR)((ULONG_PTR)DstData + BytesToCopy);
|
|
|
|
Length -= BytesToCopy;
|
|
if (Length == 0)
|
|
break;
|
|
|
|
SrcSize -= BytesToCopy;
|
|
if (SrcSize == 0) {
|
|
/* No more bytes in source buffer. Proceed to
|
|
the next buffer in the source buffer chain */
|
|
NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
|
|
if (!SrcBuffer)
|
|
break;
|
|
|
|
NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
|
|
}
|
|
}
|
|
|
|
return BytesCopied;
|
|
}
|
|
|
|
|
|
UINT CopyPacketToBuffer(
|
|
PCHAR DstData,
|
|
PNDIS_PACKET SrcPacket,
|
|
UINT SrcOffset,
|
|
UINT Length)
|
|
/*
|
|
* FUNCTION: Copies data from an NDIS packet to a buffer
|
|
* ARGUMENTS:
|
|
* DstData = Pointer to destination buffer
|
|
* SrcPacket = Pointer to source NDIS packet
|
|
* SrcOffset = Source start offset
|
|
* Length = Number of bytes to copy
|
|
* RETURNS:
|
|
* Number of bytes copied to destination buffer
|
|
* NOTES:
|
|
* The number of bytes copied may be limited by the source
|
|
* buffer size
|
|
*/
|
|
{
|
|
PNDIS_BUFFER FirstBuffer;
|
|
PVOID Address;
|
|
UINT FirstLength;
|
|
UINT TotalLength;
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("DstData (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));
|
|
|
|
NdisGetFirstBufferFromPacket(SrcPacket,
|
|
&FirstBuffer,
|
|
&Address,
|
|
&FirstLength,
|
|
&TotalLength);
|
|
|
|
return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);
|
|
}
|
|
|
|
|
|
UINT CopyPacketToBufferChain(
|
|
PNDIS_BUFFER DstBuffer,
|
|
UINT DstOffset,
|
|
PNDIS_PACKET SrcPacket,
|
|
UINT SrcOffset,
|
|
UINT Length)
|
|
/*
|
|
* FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain
|
|
* ARGUMENTS:
|
|
* DstBuffer = Pointer to destination NDIS buffer
|
|
* DstOffset = Destination start offset
|
|
* SrcPacket = Pointer to source NDIS packet
|
|
* SrcOffset = Source start offset
|
|
* Length = Number of bytes to copy
|
|
* RETURNS:
|
|
* Number of bytes copied to destination buffer
|
|
* NOTES:
|
|
* The number of bytes copied may be limited by the source and
|
|
* destination buffer sizes
|
|
*/
|
|
{
|
|
PNDIS_BUFFER SrcBuffer;
|
|
PCHAR DstData, SrcData;
|
|
UINT DstSize, SrcSize;
|
|
UINT Count, Total;
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));
|
|
|
|
/* Skip DstOffset bytes in the destination buffer chain */
|
|
NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
|
|
if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
|
|
return 0;
|
|
|
|
/* Skip SrcOffset bytes in the source packet */
|
|
NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, (PVOID)&SrcData, &SrcSize, &Total);
|
|
if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
|
|
return 0;
|
|
|
|
/* Copy the data */
|
|
for (Total = 0;;) {
|
|
/* Find out how many bytes we can copy at one time */
|
|
if (Length < SrcSize)
|
|
Count = Length;
|
|
else
|
|
Count = SrcSize;
|
|
if (DstSize < Count)
|
|
Count = DstSize;
|
|
|
|
RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);
|
|
|
|
Total += Count;
|
|
Length -= Count;
|
|
if (Length == 0)
|
|
break;
|
|
|
|
DstSize -= Count;
|
|
if (DstSize == 0) {
|
|
/* No more bytes in destination buffer. Proceed to
|
|
the next buffer in the destination buffer chain */
|
|
NdisGetNextBuffer(DstBuffer, &DstBuffer);
|
|
if (!DstBuffer)
|
|
break;
|
|
|
|
NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
|
|
}
|
|
|
|
SrcSize -= Count;
|
|
if (SrcSize == 0) {
|
|
/* No more bytes in source buffer. Proceed to
|
|
the next buffer in the source buffer chain */
|
|
NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
|
|
if (!SrcBuffer)
|
|
break;
|
|
|
|
NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
|
|
}
|
|
}
|
|
|
|
return Total;
|
|
}
|
|
|
|
|
|
UINT ResizePacket(
|
|
PNDIS_PACKET Packet,
|
|
UINT Size)
|
|
/*
|
|
* FUNCTION: Resizes an NDIS packet
|
|
* ARGUMENTS:
|
|
* Packet = Pointer to packet
|
|
* Size = Number of bytes in first buffer
|
|
* RETURNS:
|
|
* Previous size of first buffer
|
|
*/
|
|
{
|
|
PNDIS_BUFFER NdisBuffer;
|
|
UINT OldSize;
|
|
|
|
NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
|
|
|
|
OldSize = NdisBuffer->ByteCount;
|
|
|
|
if (Size != OldSize)
|
|
NdisBuffer->ByteCount = Size;
|
|
|
|
return OldSize;
|
|
}
|
|
|
|
NDIS_STATUS PrependPacket( PNDIS_PACKET Packet, PCHAR Data, UINT Length,
|
|
BOOLEAN Copy ) {
|
|
PNDIS_BUFFER Buffer;
|
|
NDIS_STATUS Status;
|
|
PCHAR NewBuf;
|
|
|
|
if( Copy ) {
|
|
NewBuf = ExAllocatePoolWithTag( NonPagedPool, Length, PACKET_BUFFER_TAG );
|
|
if( !NewBuf ) return NDIS_STATUS_RESOURCES;
|
|
RtlCopyMemory( NewBuf, Data, Length );
|
|
} else NewBuf = Data;
|
|
|
|
NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewBuf, Length );
|
|
if( Status != NDIS_STATUS_SUCCESS ) {
|
|
if (Copy) ExFreePoolWithTag(NewBuf, PACKET_BUFFER_TAG);
|
|
return Status;
|
|
}
|
|
|
|
NdisChainBufferAtFront( Packet, Buffer );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
void GetDataPtr( PNDIS_PACKET Packet,
|
|
UINT Offset,
|
|
PCHAR *DataOut,
|
|
PUINT Size ) {
|
|
PNDIS_BUFFER Buffer;
|
|
|
|
NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
|
|
if( !Buffer ) return;
|
|
SkipToOffset( Buffer, Offset, DataOut, Size );
|
|
}
|
|
|
|
NDIS_STATUS AllocatePacketWithBuffer( PNDIS_PACKET *NdisPacket,
|
|
PCHAR Data, UINT Len ) {
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_BUFFER Buffer;
|
|
NDIS_STATUS Status;
|
|
PCHAR NewData;
|
|
|
|
NewData = ExAllocatePoolWithTag( NonPagedPool, Len, PACKET_BUFFER_TAG );
|
|
if( !NewData ) return NDIS_STATUS_RESOURCES;
|
|
|
|
if( Data ) RtlCopyMemory(NewData, Data, Len);
|
|
|
|
NdisAllocatePacket( &Status, &Packet, GlobalPacketPool );
|
|
if( Status != NDIS_STATUS_SUCCESS ) {
|
|
ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG );
|
|
return Status;
|
|
}
|
|
|
|
NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len );
|
|
if( Status != NDIS_STATUS_SUCCESS ) {
|
|
ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG );
|
|
FreeNdisPacket( Packet );
|
|
return Status;
|
|
}
|
|
|
|
NdisChainBufferAtFront( Packet, Buffer );
|
|
*NdisPacket = Packet;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID FreeNdisPacket
|
|
( PNDIS_PACKET Packet )
|
|
/*
|
|
* FUNCTION: Frees an NDIS packet
|
|
* ARGUMENTS:
|
|
* Packet = Pointer to NDIS packet to be freed
|
|
*/
|
|
{
|
|
PNDIS_BUFFER Buffer, NextBuffer;
|
|
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet));
|
|
|
|
/* Free all the buffers in the packet first */
|
|
NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
|
|
for (; Buffer != NULL; Buffer = NextBuffer) {
|
|
PVOID Data;
|
|
UINT Length;
|
|
|
|
NdisGetNextBuffer(Buffer, &NextBuffer);
|
|
NdisQueryBuffer(Buffer, &Data, &Length);
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("Freeing ndis buffer (0x%X)\n", Buffer));
|
|
NdisFreeBuffer(Buffer);
|
|
TI_DbgPrint(DEBUG_PBUFFER, ("Freeing exal buffer (0x%X)\n", Data));
|
|
ExFreePoolWithTag(Data, PACKET_BUFFER_TAG);
|
|
}
|
|
|
|
/* Finally free the NDIS packet discriptor */
|
|
NdisFreePacket(Packet);
|
|
}
|