/* * 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" static 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 destination 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; } 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 descriptor */ NdisFreePacket(Packet); }