2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
5 * PURPOSE: Buffer management routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
15 NdisAdjustBufferLength(
16 IN PNDIS_BUFFER Buffer
,
19 * FUNCTION: Modifies the length of an NDIS buffer
21 * Buffer = Pointer to NDIS buffer descriptor
22 * Length = New size of buffer
25 Buffer
->ByteCount
= Length
;
31 NDIS_BUFFER_TO_SPAN_PAGES(
32 IN PNDIS_BUFFER Buffer
)
34 * FUNCTION: Determines how many physical pages a buffer is made of
36 * Buffer = Pointer to NDIS buffer descriptor
39 if (MmGetMdlByteCount(Buffer
) == 0)
42 return ADDRESS_AND_SIZE_TO_SPAN_PAGES(
43 MmGetMdlVirtualAddress(Buffer
),
44 MmGetMdlByteCount(Buffer
));
51 OUT PNDIS_STATUS Status
,
52 OUT PNDIS_BUFFER
* Buffer
,
53 IN NDIS_HANDLE PoolHandle
,
54 IN PVOID VirtualAddress
,
57 * FUNCTION: Allocates an NDIS buffer descriptor
59 * Status = Address of buffer for status
60 * Buffer = Address of buffer for NDIS buffer descriptor
61 * PoolHandle = Handle returned by NdisAllocateBufferPool
62 * VirtualAddress = Pointer to virtual address of data buffer
63 * Length = Number of bytes in data buffer
68 PNDIS_BUFFER_POOL Pool
= (PNDIS_BUFFER_POOL
)PoolHandle
;
70 NDIS_DbgPrint(MAX_TRACE
, ("Status (0x%X) Buffer (0x%X) PoolHandle (0x%X) "
71 "VirtualAddress (0x%X) Length (%d)\n",
72 Status
, Buffer
, PoolHandle
, VirtualAddress
, Length
));
74 KeAcquireSpinLock(&Pool
->SpinLock
, &OldIrql
);
77 Temp
= Pool
->FreeList
;
78 Pool
->FreeList
= Temp
->Next
;
80 KeReleaseSpinLock(&Pool
->SpinLock
, OldIrql
);
85 MmInitializeMdl(&Temp
->Mdl
, VirtualAddress
, Length
);
86 Temp
->Mdl
.MdlFlags
|= (MDL_SOURCE_IS_NONPAGED_POOL
| MDL_ALLOCATED_FIXED_SIZE
);
87 Temp
->Mdl
.MappedSystemVa
= VirtualAddress
;
89 Temp
->Mdl
.Next
= (PMDL
)NULL
;
90 Temp
->Mdl
.Size
= (CSHORT
)(sizeof(MDL
) +
91 (ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress
, Length
) * sizeof(ULONG
)));
92 Temp
->Mdl
.MdlFlags
= (MDL_SOURCE_IS_NONPAGED_POOL
| MDL_ALLOCATED_FIXED_SIZE
);
93 ; Temp
->Mdl
.StartVa
= (PVOID
)PAGE_ROUND_DOWN(VirtualAddress
);
94 Temp
->Mdl
.ByteOffset
= (ULONG_PTR
)(VirtualAddress
- PAGE_ROUND_DOWN(VirtualAddress
));
95 Temp
->Mdl
.ByteCount
= Length
;
96 Temp
->Mdl
.MappedSystemVa
= VirtualAddress
;
98 //Temp->Mdl.Process = PsGetCurrentProcess();
100 Temp
->Mdl
.Process
= NULL
;
104 Temp
->BufferPool
= Pool
;
106 *Buffer
= (PNDIS_BUFFER
)Temp
;
107 *Status
= NDIS_STATUS_SUCCESS
;
109 KeReleaseSpinLock(&Pool
->SpinLock
, OldIrql
);
110 *Status
= NDIS_STATUS_FAILURE
;
117 NdisAllocateBufferPool(
118 OUT PNDIS_STATUS Status
,
119 OUT PNDIS_HANDLE PoolHandle
,
120 IN UINT NumberOfDescriptors
)
122 * FUNCTION: Allocates storage for an NDIS buffer pool
124 * Status = Address of buffer for status
125 * PoolHandle = Address of buffer for pool handle
126 * NumberOfDescriptors = Size of buffer pool in number of descriptors
130 PNDIS_BUFFER_POOL Pool
;
131 PNETWORK_HEADER Buffer
;
133 NDIS_DbgPrint(MAX_TRACE
, ("Status (0x%X) PoolHandle (0x%X) NumberOfDescriptors (%d).\n",
134 Status
, PoolHandle
, NumberOfDescriptors
));
136 Pool
= ExAllocatePool(NonPagedPool
,
137 sizeof(NDIS_BUFFER_POOL
) +
138 sizeof(NETWORK_HEADER
) *
139 NumberOfDescriptors
);
141 KeInitializeSpinLock(&Pool
->SpinLock
);
143 if (NumberOfDescriptors
> 0) {
144 Buffer
= &Pool
->Buffers
[0];
145 Pool
->FreeList
= Buffer
;
146 for (i
= 1; i
< NumberOfDescriptors
; i
++) {
147 Buffer
->Next
= &Pool
->Buffers
[i
];
148 Buffer
= Buffer
->Next
;
152 Pool
->FreeList
= NULL
;
154 *Status
= NDIS_STATUS_SUCCESS
;
155 *PoolHandle
= (PNDIS_HANDLE
)Pool
;
157 *Status
= NDIS_STATUS_RESOURCES
;
164 OUT PNDIS_STATUS Status
,
165 OUT PNDIS_PACKET
* Packet
,
166 IN NDIS_HANDLE PoolHandle
)
168 * FUNCTION: Allocates an NDIS packet descriptor
170 * Status = Address of buffer for status
171 * Packet = Address of buffer for packet descriptor
172 * PoolHandle = Handle returned by NdisAllocatePacketPool
177 PNDIS_PACKET_POOL Pool
= (PNDIS_PACKET_POOL
)PoolHandle
;
179 NDIS_DbgPrint(MAX_TRACE
, ("Status (0x%X) Packet (0x%X) PoolHandle (0x%X).\n",
180 Status
, Packet
, PoolHandle
));
182 KeAcquireSpinLock(&Pool
->SpinLock
.SpinLock
, &OldIrql
);
184 if (Pool
->FreeList
) {
185 Temp
= Pool
->FreeList
;
186 Pool
->FreeList
= (PNDIS_PACKET
)Temp
->Private
.Head
;
188 KeReleaseSpinLock(&Pool
->SpinLock
.SpinLock
, OldIrql
);
190 RtlZeroMemory(&Temp
->Private
, sizeof(NDIS_PACKET_PRIVATE
));
191 Temp
->Private
.Pool
= Pool
;
194 *Status
= NDIS_STATUS_SUCCESS
;
196 *Status
= NDIS_STATUS_RESOURCES
;
197 KeReleaseSpinLock(&Pool
->SpinLock
.SpinLock
, OldIrql
);
204 NdisAllocatePacketPool(
205 OUT PNDIS_STATUS Status
,
206 OUT PNDIS_HANDLE PoolHandle
,
207 IN UINT NumberOfDescriptors
,
208 IN UINT ProtocolReservedLength
)
210 * FUNCTION: Allocates storage for an NDIS packet pool
212 * Status = Address of buffer for status
213 * PoolHandle = Address of buffer for pool handle
214 * NumberOfDescriptors = Size of packet pool in number of descriptors
215 * ProtocolReservedLength = Size of protocol reserved area in bytes
218 PNDIS_PACKET_POOL Pool
;
219 UINT Size
, Length
, i
;
220 PNDIS_PACKET Packet
, NextPacket
;
222 NDIS_DbgPrint(MAX_TRACE
, ("Status (0x%X) PoolHandle (0x%X) "
223 "NumberOfDescriptors (%d) ProtocolReservedLength (%d).\n",
224 Status
, PoolHandle
, NumberOfDescriptors
, ProtocolReservedLength
));
226 Length
= sizeof(NDIS_PACKET
) + ProtocolReservedLength
;
227 Size
= sizeof(NDIS_PACKET_POOL
) + Length
* NumberOfDescriptors
;
229 Pool
= ExAllocatePool(NonPagedPool
, Size
);
231 KeInitializeSpinLock(&Pool
->SpinLock
.SpinLock
);
232 Pool
->PacketLength
= Length
;
234 if (NumberOfDescriptors
> 0) {
235 Packet
= (PNDIS_PACKET
)&Pool
->Buffer
;
236 Pool
->FreeList
= Packet
;
238 NextPacket
= (PNDIS_PACKET
)((ULONG_PTR
)Packet
+ Length
);
239 for (i
= 1; i
< NumberOfDescriptors
; i
++) {
240 Packet
->Private
.Head
= (PNDIS_BUFFER
)NextPacket
;
242 NextPacket
= (PNDIS_PACKET
)((ULONG_PTR
)Packet
+ Length
);
244 Packet
->Private
.Head
= NULL
;
246 Pool
->FreeList
= NULL
;
248 *Status
= NDIS_STATUS_SUCCESS
;
249 *PoolHandle
= (PNDIS_HANDLE
)Pool
;
251 *Status
= NDIS_STATUS_RESOURCES
;
257 NdisAllocatePacketPoolEx(
258 OUT PNDIS_STATUS Status
,
259 OUT PNDIS_HANDLE PoolHandle
,
260 IN UINT NumberOfDescriptors
,
261 IN UINT NumberOfOverflowDescriptors
,
262 IN UINT ProtocolReservedLength
)
277 IN PNDIS_BUFFER Buffer
)
293 NdisBufferVirtualAddress(
294 IN PNDIS_BUFFER Buffer
)
311 OUT PNDIS_STATUS Status
,
312 OUT PNDIS_BUFFER
*Buffer
,
313 IN NDIS_HANDLE PoolHandle
,
314 IN PVOID MemoryDescriptor
,
318 * FUNCTION: Returns a new buffer descriptor for a (partial) buffer
320 * Status = Address of a buffer to place status of operation
321 * Buffer = Address of a buffer to place new buffer descriptor
322 * PoolHandle = Handle returned by NdisAllocateBufferPool
323 * MemoryDescriptor = Pointer to a memory descriptor (possibly NDIS_BUFFER)
324 * Offset = Offset in buffer to start copying
325 * Length = Number of bytes to copy
328 *Status
= NDIS_STATUS_FAILURE
;
332 __inline ULONG
SkipToOffset(
338 * FUNCTION: Skips Offset bytes into a buffer chain
340 * Buffer = Pointer to NDIS buffer
341 * Offset = Number of bytes to skip
342 * Data = Address of a pointer that on return will contain the
343 * address of the offset in the buffer
344 * Size = Address of a pointer that on return will contain the
345 * size of the destination buffer
347 * Offset into buffer, -1 if buffer chain was smaller than Offset bytes
359 NdisQueryBuffer(Buffer
, Data
, Size
);
361 if (Offset
< *Size
) {
369 NdisGetNextBuffer(Buffer
, &Buffer
);
372 *Data
= (PVOID
)Address
;
380 NdisCopyFromPacketToPacket(
381 IN PNDIS_PACKET Destination
,
382 IN UINT DestinationOffset
,
384 IN PNDIS_PACKET Source
,
385 IN UINT SourceOffset
,
386 OUT PUINT BytesCopied
)
388 * FUNCTION: Copies data from one packet to another
390 * Destination = Pointer to packet to copy data to
391 * DestinationOffset = Offset in destination packet to copy data to
392 * BytesToCopy = Number of bytes to copy
393 * Source = Pointer to packet descriptor to copy from
394 * SourceOffset = Offset in source packet to start copying from
395 * BytesCopied = Address of buffer to place number of bytes copied
398 PNDIS_BUFFER SrcBuffer
;
399 PNDIS_BUFFER DstBuffer
;
400 PVOID DstData
, SrcData
;
401 UINT DstSize
, SrcSize
;
406 /* Skip DestinationOffset bytes in the destination packet */
407 NdisGetFirstBufferFromPacket(Destination
, &DstBuffer
, &DstData
, &DstSize
, &Total
);
408 if (SkipToOffset(DstBuffer
, DestinationOffset
, &DstData
, &DstSize
) == -1)
411 /* Skip SourceOffset bytes in the source packet */
412 NdisGetFirstBufferFromPacket(Source
, &SrcBuffer
, &SrcData
, &SrcSize
, &Total
);
413 if (SkipToOffset(SrcBuffer
, SourceOffset
, &SrcData
, &SrcSize
) == -1)
418 /* Find out how many bytes we can copy at one time */
419 if (BytesToCopy
< SrcSize
)
426 RtlCopyMemory(DstData
, SrcData
, Count
);
429 BytesToCopy
-= Count
;
430 if (BytesToCopy
== 0)
435 /* No more bytes in destination buffer. Proceed to
436 the next buffer in the destination buffer chain */
437 NdisGetNextBuffer(DstBuffer
, &DstBuffer
);
441 NdisQueryBuffer(DstBuffer
, &DstData
, &DstSize
);
446 /* No more bytes in source buffer. Proceed to
447 the next buffer in the source buffer chain */
448 NdisGetNextBuffer(SrcBuffer
, &SrcBuffer
);
452 NdisQueryBuffer(SrcBuffer
, &SrcData
, &SrcSize
);
456 *BytesCopied
= Total
;
462 NdisDprAllocatePacket(
463 OUT PNDIS_STATUS Status
,
464 OUT PNDIS_PACKET
*Packet
,
465 IN NDIS_HANDLE PoolHandle
)
467 * FUNCTION: Allocates a packet at IRQL DISPATCH_LEVEL
469 * Status = Address of buffer to place status of operation
470 * Packet = Address of buffer to place a pointer to a packet descriptor
471 * PoolHandle = Handle returned by NdisAllocatePacketPool
479 NdisDprAllocatePacketNonInterlocked(
480 OUT PNDIS_STATUS Status
,
481 OUT PNDIS_PACKET
*Packet
,
482 IN NDIS_HANDLE PoolHandle
)
484 * FUNCTION: Allocates a packet at IRQL DISPATCH_LEVEL (w/o synchronization)
486 * Status = Address of buffer to place status of operation
487 * Packet = Address of buffer to place a pointer to a packet descriptor
488 * PoolHandle = Handle returned by NdisAllocatePacketPool
491 *Status
= NDIS_STATUS_FAILURE
;
498 IN PNDIS_PACKET Packet
)
500 * FUNCTION: Frees a packet at IRQL DISPATCH_LEVEL
502 * Packet = Pointer to packet to free
510 NdisDprFreePacketNonInterlocked(
511 IN PNDIS_PACKET Packet
)
513 * FUNCTION: Frees a packet at IRQL DISPATCH_LEVEL (w/o synchronization)
515 * Packet = Pointer to packet to free
524 IN NDIS_HANDLE PoolHandle
)
526 * FUNCTION: Frees storage allocated for an NDIS buffer pool
528 * PoolHandle = Handle returned by NdisAllocateBufferPool
531 ExFreePool((PVOID
)PoolHandle
);
538 IN NDIS_HANDLE PoolHandle
)
540 * FUNCTION: Frees storage allocated for an NDIS packet pool
542 * PoolHandle = Handle returned by NdisAllocatePacketPool
545 ExFreePool((PVOID
)PoolHandle
);
552 IN PNDIS_BUFFER Buffer
)
554 * FUNCTION: Puts an NDIS buffer descriptor back in it's pool
556 * Buffer = Pointer to buffer descriptor
560 PNDIS_BUFFER_POOL Pool
;
561 PNETWORK_HEADER Temp
= (PNETWORK_HEADER
)Buffer
;
563 NDIS_DbgPrint(MAX_TRACE
, ("Buffer (0x%X).\n", Buffer
));
565 Pool
= Temp
->BufferPool
;
567 KeAcquireSpinLock(&Pool
->SpinLock
, &OldIrql
);
568 Buffer
->Next
= (PMDL
)Pool
->FreeList
;
569 Pool
->FreeList
= (PNETWORK_HEADER
)Buffer
;
570 KeReleaseSpinLock(&Pool
->SpinLock
, OldIrql
);
577 IN PNDIS_PACKET Packet
)
579 * FUNCTION: Puts an NDIS packet descriptor back in it's pool
581 * Packet = Pointer to packet descriptor
586 NDIS_DbgPrint(MAX_TRACE
, ("Packet (0x%X).\n", Packet
));
588 KeAcquireSpinLock(&Packet
->Private
.Pool
->SpinLock
.SpinLock
, &OldIrql
);
589 Packet
->Private
.Head
= (PNDIS_BUFFER
)Packet
->Private
.Pool
->FreeList
;
590 Packet
->Private
.Pool
->FreeList
= Packet
;
591 KeReleaseSpinLock(&Packet
->Private
.Pool
->SpinLock
.SpinLock
, OldIrql
);
597 NdisGetBufferPhysicalArraySize(
598 IN PNDIS_BUFFER Buffer
,
601 * FUNCTION: Returns number of discontiguous physical blocks backing a buffer
603 * Buffer = Pointer to buffer descriptor
604 * ArraySize = Address of buffer to place number of physical blocks
613 NdisGetFirstBufferFromPacket(
614 IN PNDIS_PACKET _Packet
,
615 OUT PNDIS_BUFFER
*_FirstBuffer
,
616 OUT PVOID
*_FirstBufferVA
,
617 OUT PUINT _FirstBufferLength
,
618 OUT PUINT _TotalBufferLength
)
627 IN PNDIS_PACKET
*PacketsToReturn
,
628 IN UINT NumberOfPackets
)
630 * FUNCTION: Releases ownership of one or more packets
632 * PacketsToReturn = Pointer to an array of pointers to packet descriptors
633 * NumberOfPackets = Number of pointers in descriptor pointer array
643 IN NDIS_HANDLE PoolHandle
)
660 IN PNDIS_BUFFER Buffer
,
661 OUT PVOID
*VirtualAddress OPTIONAL
,
665 * Queries an NDIS buffer for information
667 * Buffer = Pointer to NDIS buffer to query
668 * VirtualAddress = Address of buffer to place virtual address
669 * Length = Address of buffer to place length of buffer
672 if (VirtualAddress
!= NULL
)
673 *(PVOID
*)VirtualAddress
= MmGetSystemAddressForMdl(Buffer
);
675 *Length
= MmGetMdlByteCount(Buffer
);
681 NdisQueryBufferOffset(
682 IN PNDIS_BUFFER Buffer
,
692 NdisUnchainBufferAtBack(
693 IN OUT PNDIS_PACKET Packet
,
694 OUT PNDIS_BUFFER
*Buffer
)
697 * Removes the last buffer in a packet
699 * Packet = Pointer to NDIS packet
700 * Buffer = Address of buffer to place pointer to removed NDIS buffer
703 PNDIS_BUFFER NdisBuffer
, Previous
;
705 NdisQueryPacket(Packet
,
716 while (NdisBuffer
->Next
) {
717 Previous
= NdisBuffer
;
718 NdisBuffer
= NdisBuffer
->Next
;
722 Previous
->Next
= NULL
;
723 Packet
->Private
.Tail
= Previous
;
725 Packet
->Private
.Head
= NULL
;
726 Packet
->Private
.Tail
= NULL
;
729 Packet
->Private
.ValidCounts
= FALSE
;
731 *Buffer
= NdisBuffer
;
737 NdisUnchainBufferAtFront(
738 IN OUT PNDIS_PACKET Packet
,
739 OUT PNDIS_BUFFER
*Buffer
)
742 * Removes the first buffer in a packet
744 * Packet = Pointer to NDIS packet
745 * Buffer = Address of buffer to place pointer to removed NDIS buffer
748 PNDIS_BUFFER NdisBuffer
;
750 NdisQueryPacket(Packet
,
760 Packet
->Private
.Head
= NdisBuffer
->Next
;
762 if (!NdisBuffer
->Next
)
763 Packet
->Private
.Tail
= NULL
;
765 NdisBuffer
->Next
= NULL
;
767 Packet
->Private
.ValidCounts
= FALSE
;
769 *Buffer
= NdisBuffer
;