xref: /reactos/drivers/network/ndis/ndis/buffer.c (revision 321bcc05)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS NDIS library
4  * FILE:        ndis/buffer.c
5  * PURPOSE:     Buffer management routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 
11 #include <ndissys.h>
12 
13 __inline ULONG SkipToOffset(
14     IN PNDIS_BUFFER Buffer,
15     IN UINT Offset,
16     IN OUT PUCHAR *Data,
17     IN OUT PUINT Size)
18 /*
19  * FUNCTION: Skips Offset bytes into a buffer chain
20  * ARGUMENTS:
21  *     Buffer = Pointer to NDIS buffer
22  *     Offset = Number of bytes to skip
23  *     Data   = Address of a pointer that on return will contain the
24  *              address of the offset in the buffer
25  *     Size   = Address of a pointer that on return will contain the
26  *              size of the destination buffer
27  * RETURNS:
28  *     Offset into buffer, -1 if buffer chain was smaller than Offset bytes
29  * NOTES:
30  *     Buffer may be NULL
31  */
32 {
33     for (;;) {
34 
35         if (!Buffer)
36             return 0xFFFFFFFF;
37 
38         NdisQueryBuffer(Buffer, (PVOID)Data, Size);
39 
40         if (Offset < *Size) {
41             *Data  = (PUCHAR) ((ULONG_PTR) *Data + Offset);
42             *Size -= Offset;
43             break;
44         }
45 
46         Offset -= *Size;
47 
48         NdisGetNextBuffer(Buffer, &Buffer);
49     }
50 
51     return Offset;
52 }
53 
54 UINT CopyBufferToBufferChain(
55     PNDIS_BUFFER DstBuffer,
56     UINT DstOffset,
57     PUCHAR SrcData,
58     UINT Length)
59 /*
60  * FUNCTION: Copies data from a buffer to an NDIS buffer chain
61  * ARGUMENTS:
62  *     DstBuffer = Pointer to destination NDIS buffer
63  *     DstOffset = Destination start offset
64  *     SrcData   = Pointer to source buffer
65  *     Length    = Number of bytes to copy
66  * RETURNS:
67  *     Number of bytes copied to destination buffer
68  * NOTES:
69  *     The number of bytes copied may be limited by the destination
70  *     buffer size
71  */
72 {
73     UINT BytesCopied, BytesToCopy, DstSize;
74     PUCHAR DstData;
75 
76     NDIS_DbgPrint(MAX_TRACE, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcData (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));
77 
78     /* Skip DstOffset bytes in the destination buffer chain */
79     if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == 0xFFFFFFFF)
80         return 0;
81 
82     /* Start copying the data */
83     BytesCopied = 0;
84     for (;;) {
85         BytesToCopy = MIN(DstSize, Length);
86 
87         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
88         BytesCopied += BytesToCopy;
89         SrcData      = (PUCHAR) ((ULONG_PTR) SrcData + BytesToCopy);
90 
91         Length -= BytesToCopy;
92         if (Length == 0)
93             break;
94 
95         DstSize -= BytesToCopy;
96         if (DstSize == 0) {
97             /* No more bytes in desination buffer. Proceed to
98                the next buffer in the destination buffer chain */
99             NdisGetNextBuffer(DstBuffer, &DstBuffer);
100             if (!DstBuffer)
101                 break;
102 
103             NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
104         }
105     }
106 
107     return BytesCopied;
108 }
109 
110 
111 UINT CopyBufferChainToBuffer(
112     PUCHAR DstData,
113     PNDIS_BUFFER SrcBuffer,
114     UINT SrcOffset,
115     UINT Length)
116 /*
117  * FUNCTION: Copies data from an NDIS buffer chain to a buffer
118  * ARGUMENTS:
119  *     DstData   = Pointer to destination buffer
120  *     SrcBuffer = Pointer to source NDIS buffer
121  *     SrcOffset = Source start offset
122  *     Length    = Number of bytes to copy
123  * RETURNS:
124  *     Number of bytes copied to destination buffer
125  * NOTES:
126  *     The number of bytes copied may be limited by the source
127  *     buffer size
128  */
129 {
130     UINT BytesCopied, BytesToCopy, SrcSize;
131     PUCHAR SrcData;
132 
133     NDIS_DbgPrint(MAX_TRACE, ("DstData 0x%X  SrcBuffer 0x%X  SrcOffset 0x%X  Length %d\n",DstData,SrcBuffer, SrcOffset, Length));
134 
135     /* Skip SrcOffset bytes in the source buffer chain */
136     if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == 0xFFFFFFFF)
137         return 0;
138 
139     /* Start copying the data */
140     BytesCopied = 0;
141     for (;;) {
142         BytesToCopy = MIN(SrcSize, Length);
143 
144         NDIS_DbgPrint(MAX_TRACE, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
145 
146         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
147         BytesCopied += BytesToCopy;
148         DstData      = (PUCHAR)((ULONG_PTR) DstData + BytesToCopy);
149 
150         Length -= BytesToCopy;
151         if (Length == 0)
152             break;
153 
154         SrcSize -= BytesToCopy;
155         if (SrcSize == 0) {
156             /* No more bytes in source buffer. Proceed to
157                the next buffer in the source buffer chain */
158             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
159             if (!SrcBuffer)
160                 break;
161 
162             NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
163         }
164     }
165 
166     return BytesCopied;
167 }
168 
169 
170 UINT CopyPacketToBuffer(
171     PUCHAR DstData,
172     PNDIS_PACKET SrcPacket,
173     UINT SrcOffset,
174     UINT Length)
175 /*
176  * FUNCTION: Copies data from an NDIS packet to a buffer
177  * ARGUMENTS:
178  *     DstData   = Pointer to destination buffer
179  *     SrcPacket = Pointer to source NDIS packet
180  *     SrcOffset = Source start offset
181  *     Length    = Number of bytes to copy
182  * RETURNS:
183  *     Number of bytes copied to destination buffer
184  * NOTES:
185  *     The number of bytes copied may be limited by the source
186  *     buffer size
187  */
188 {
189     PNDIS_BUFFER FirstBuffer;
190     PVOID Address;
191     UINT FirstLength;
192     UINT TotalLength;
193 
194     NDIS_DbgPrint(MAX_TRACE, ("DstData (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));
195 
196     NdisGetFirstBufferFromPacket(SrcPacket,
197                                  &FirstBuffer,
198                                  &Address,
199                                  &FirstLength,
200                                  &TotalLength);
201 
202     return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);
203 }
204 
205 
206 UINT CopyPacketToBufferChain(
207     PNDIS_BUFFER DstBuffer,
208     UINT DstOffset,
209     PNDIS_PACKET SrcPacket,
210     UINT SrcOffset,
211     UINT Length)
212 /*
213  * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain
214  * ARGUMENTS:
215  *     DstBuffer = Pointer to destination NDIS buffer
216  *     DstOffset = Destination start offset
217  *     SrcPacket = Pointer to source NDIS packet
218  *     SrcOffset = Source start offset
219  *     Length    = Number of bytes to copy
220  * RETURNS:
221  *     Number of bytes copied to destination buffer
222  * NOTES:
223  *     The number of bytes copied may be limited by the source and
224  *     destination buffer sizes
225  */
226 {
227     PNDIS_BUFFER SrcBuffer;
228     PUCHAR DstData, SrcData;
229     UINT DstSize, SrcSize;
230     UINT Count, Total;
231 
232     NDIS_DbgPrint(MAX_TRACE, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));
233 
234     /* Skip DstOffset bytes in the destination buffer chain */
235     NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
236     if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == 0xFFFFFFFF)
237         return 0;
238     /* Skip SrcOffset bytes in the source packet */
239     NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, (PVOID*)&SrcData, &SrcSize, &Total);
240     if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == 0xFFFFFFFF)
241         return 0;
242     /* Copy the data */
243     for (Total = 0;;) {
244         /* Find out how many bytes we can copy at one time */
245         if (Length < SrcSize)
246             Count = Length;
247         else
248             Count = SrcSize;
249         if (DstSize < Count)
250             Count = DstSize;
251 
252         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);
253 
254         Total  += Count;
255         Length -= Count;
256         if (Length == 0)
257             break;
258 
259         DstSize -= Count;
260         if (DstSize == 0) {
261             /* No more bytes in destination buffer. Proceed to
262                the next buffer in the destination buffer chain */
263             NdisGetNextBuffer(DstBuffer, &DstBuffer);
264             if (!DstBuffer)
265                 break;
266 
267             NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
268         }
269 
270         SrcSize -= Count;
271         if (SrcSize == 0) {
272             /* No more bytes in source buffer. Proceed to
273                the next buffer in the source buffer chain */
274             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
275             if (!SrcBuffer)
276                 break;
277 
278             NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
279         }
280     }
281 
282     return Total;
283 }
284 
285 
286 /*
287  * @implemented
288  */
289 #undef NdisAdjustBufferLength
290 VOID
291 EXPORT
292 NdisAdjustBufferLength(
293     IN PNDIS_BUFFER Buffer,
294     IN UINT         Length)
295 /*
296  * FUNCTION: Modifies the length of an NDIS buffer
297  * ARGUMENTS:
298  *     Buffer = Pointer to NDIS buffer descriptor
299  *     Length = New size of buffer
300  */
301 {
302     Buffer->ByteCount = Length;
303 }
304 
305 
306 /*
307  * @implemented
308  */
309 #undef NDIS_BUFFER_TO_SPAN_PAGES
310 ULONG
311 EXPORT
312 NDIS_BUFFER_TO_SPAN_PAGES(
313     IN  PNDIS_BUFFER    Buffer)
314 /*
315  * FUNCTION: Determines how many physical pages a buffer is made of
316  * ARGUMENTS:
317  *     Buffer = Pointer to NDIS buffer descriptor
318  */
319 {
320     if (MmGetMdlByteCount(Buffer) == 0)
321         return 1;
322 
323     return ADDRESS_AND_SIZE_TO_SPAN_PAGES(
324             MmGetMdlVirtualAddress(Buffer),
325             MmGetMdlByteCount(Buffer));
326 }
327 
328 
329 /*
330  * @implemented
331  */
332 VOID
333 EXPORT
334 NdisAllocateBuffer(
335     OUT PNDIS_STATUS    Status,
336     OUT PNDIS_BUFFER    * Buffer,
337     IN  NDIS_HANDLE     PoolHandle,
338     IN  PVOID           VirtualAddress,
339     IN  UINT            Length)
340 /*
341  * FUNCTION: Allocates an NDIS buffer descriptor
342  * ARGUMENTS:
343  *     Status         = Address of buffer for status
344  *     Buffer         = Address of buffer for NDIS buffer descriptor
345  *     PoolHandle     = Handle returned by NdisAllocateBufferPool
346  *     VirtualAddress = Pointer to virtual address of data buffer
347  *     Length         = Number of bytes in data buffer
348  */
349 {
350     ASSERT(VirtualAddress != NULL);
351     ASSERT(Length > 0);
352 
353     *Buffer = IoAllocateMdl(VirtualAddress, Length, FALSE, FALSE, NULL);
354     if (*Buffer != NULL) {
355         MmBuildMdlForNonPagedPool(*Buffer);
356         (*Buffer)->Next = NULL;
357         *Status = NDIS_STATUS_SUCCESS;
358     } else {
359         NDIS_DbgPrint(MIN_TRACE, ("IoAllocateMdl failed (%x, %lx)\n", VirtualAddress, Length));
360         *Status = NDIS_STATUS_FAILURE;
361     }
362 }
363 
364 
365 /*
366  * @implemented
367  */
368 VOID
369 EXPORT
370 NdisAllocateBufferPool(
371     OUT PNDIS_STATUS    Status,
372     OUT PNDIS_HANDLE    PoolHandle,
373     IN  UINT            NumberOfDescriptors)
374 /*
375  * FUNCTION: Allocates storage for an NDIS buffer pool
376  * ARGUMENTS:
377  *     Status              = Address of buffer for status
378  *     PoolHandle          = Address of buffer for pool handle
379  *     NumberOfDescriptors = Size of buffer pool in number of descriptors
380  */
381 {
382     *Status = NDIS_STATUS_SUCCESS;
383     *PoolHandle = 0;
384 }
385 
386 
387 /*
388  * @implemented
389  */
390 VOID
391 EXPORT
392 NdisAllocatePacket(
393     OUT PNDIS_STATUS    Status,
394     OUT PNDIS_PACKET    * Packet,
395     IN  NDIS_HANDLE     PoolHandle)
396 /*
397  * FUNCTION: Allocates an NDIS packet descriptor
398  * ARGUMENTS:
399  *     Status     = Address of buffer for status
400  *     Packet     = Address of buffer for packet descriptor
401  *     PoolHandle = Handle returned by NdisAllocatePacketPool
402  */
403 {
404     PNDISI_PACKET_POOL Pool = (PNDISI_PACKET_POOL)PoolHandle;
405 
406     KeAcquireSpinLock(&Pool->SpinLock.SpinLock, &Pool->SpinLock.OldIrql);
407     NdisDprAllocatePacketNonInterlocked(Status,
408                                         Packet,
409                                         PoolHandle);
410     KeReleaseSpinLock(&Pool->SpinLock.SpinLock, Pool->SpinLock.OldIrql);
411 }
412 
413 
414 /*
415  * @implemented
416  */
417 VOID
418 EXPORT
419 NdisAllocatePacketPool(
420     OUT PNDIS_STATUS    Status,
421     OUT PNDIS_HANDLE    PoolHandle,
422     IN  UINT            NumberOfDescriptors,
423     IN  UINT            ProtocolReservedLength)
424 /*
425  * FUNCTION: Allocates storage for an NDIS packet pool
426  * ARGUMENTS:
427  *     Status                 = Address of buffer for status
428  *     PoolHandle             = Address of buffer for pool handle
429  *     NumberOfDescriptors    = Size of packet pool in number of descriptors
430  *     ProtocolReservedLength = Size of protocol reserved area in bytes
431  */
432 {
433     NdisAllocatePacketPoolEx(
434         Status,
435         PoolHandle,
436         NumberOfDescriptors,
437         0,
438         ProtocolReservedLength);
439 }
440 
441 
442 /*
443  * @implemented
444  */
445 VOID
446 EXPORT
447 NdisAllocatePacketPoolEx(
448     OUT PNDIS_STATUS    Status,
449     OUT PNDIS_HANDLE    PoolHandle,
450     IN  UINT            NumberOfDescriptors,
451     IN  UINT            NumberOfOverflowDescriptors,
452     IN  UINT            ProtocolReservedLength)
453 /*
454  * FUNCTION:
455  * ARGUMENTS:
456  * NOTES:
457  *    NDIS 5.0
458  */
459 {
460     PNDISI_PACKET_POOL Pool;
461     UINT Size, Length, i;
462     PNDIS_PACKET Packet, NextPacket;
463 
464     NDIS_DbgPrint(MAX_TRACE, ("Status (0x%X)  PoolHandle (0x%X)  "
465         "NumberOfDescriptors (%d)  ProtocolReservedLength (%d).\n",
466         Status, PoolHandle, NumberOfDescriptors, ProtocolReservedLength));
467 
468     *PoolHandle = NULL;
469 
470     if (NumberOfDescriptors > 0xffff)
471     {
472         NDIS_DbgPrint(MIN_TRACE, ("Invalid number of descriptors (%lx)\n", NumberOfDescriptors))
473         *Status = NDIS_STATUS_RESOURCES;
474     }
475     else
476     {
477         NumberOfDescriptors += NumberOfOverflowDescriptors;
478         if (NumberOfDescriptors > 0xffff)
479         {
480             NDIS_DbgPrint(MIN_TRACE, ("Total number of descriptors > 0xffff (%lx)\n", NumberOfDescriptors));
481             NumberOfDescriptors = 0xffff;
482         }
483 
484         Length = sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) +
485                  sizeof(NDIS_PACKET_EXTENSION) + ProtocolReservedLength;
486         Size   = sizeof(NDISI_PACKET_POOL) + Length * NumberOfDescriptors;
487 
488         Pool   = ExAllocatePool(NonPagedPool, Size);
489         if (Pool)
490         {
491             KeInitializeSpinLock(&Pool->SpinLock.SpinLock);
492             Pool->PacketLength = Length;
493 
494             if (NumberOfDescriptors > 0)
495             {
496                 Packet         = (PNDIS_PACKET)&Pool->Buffer;
497                 Pool->FreeList = Packet;
498 
499                 NextPacket = (PNDIS_PACKET)((ULONG_PTR)Packet + Length);
500                 for (i = 1; i < NumberOfDescriptors; i++)
501                 {
502                     Packet->Reserved[0]  = (ULONG_PTR)NextPacket;
503                     Packet               = NextPacket;
504                     NextPacket           = (PNDIS_PACKET)((ULONG_PTR)Packet + Length);
505                 }
506                 Packet->Reserved[0] = 0;
507             }
508             else {
509                 NDIS_DbgPrint(MIN_TRACE, ("Attempted to allocate a packet pool with 0 descriptors\n"));
510                 Pool->FreeList = NULL;
511             }
512 
513             *Status     = NDIS_STATUS_SUCCESS;
514             *PoolHandle = (PNDIS_HANDLE)Pool;
515         } else {
516             *Status = NDIS_STATUS_RESOURCES;
517         }
518     }
519 }
520 
521 
522 /*
523  * @implemented
524  */
525 #undef NdisBufferLength
526 ULONG
527 EXPORT
528 NdisBufferLength(
529     IN  PNDIS_BUFFER    Buffer)
530 /*
531  * FUNCTION: Modifies the length of an NDIS buffer
532  * ARGUMENTS:
533  *     Buffer = Pointer to NDIS buffer descriptor
534  *     Length = New size of buffer
535  * NOTES:
536  *    NDIS 5.0
537  * RETURNS:
538  *     Length of NDIS buffer
539  */
540 {
541     return MmGetMdlByteCount(Buffer);
542 }
543 
544 
545 /*
546  * @implemented
547  */
548 #undef NdisBufferVirtualAddress
549 PVOID
550 EXPORT
551 NdisBufferVirtualAddress(
552     IN  PNDIS_BUFFER    Buffer)
553 /*
554  * FUNCTION:
555  * ARGUMENTS:
556  * NOTES:
557  *    NDIS 5.0
558  */
559 {
560     return MmGetSystemAddressForMdl(Buffer);
561 }
562 
563 
564 /*
565  * @implemented
566  */
567 VOID
568 EXPORT
569 NdisCopyFromPacketToPacket(
570     IN  PNDIS_PACKET    Destination,
571     IN  UINT            DestinationOffset,
572     IN  UINT            BytesToCopy,
573     IN  PNDIS_PACKET    Source,
574     IN  UINT            SourceOffset,
575     OUT PUINT           BytesCopied)
576 /*
577  * FUNCTION: Copies data from one packet to another
578  * ARGUMENTS:
579  *     Destination       = Pointer to packet to copy data to
580  *     DestinationOffset = Offset in destination packet to copy data to
581  *     BytesToCopy       = Number of bytes to copy
582  *     Source            = Pointer to packet descriptor to copy from
583  *     SourceOffset      = Offset in source packet to start copying from
584  *     BytesCopied       = Address of buffer to place number of bytes copied
585  */
586 {
587     PNDIS_BUFFER SrcBuffer;
588     PNDIS_BUFFER DstBuffer;
589     PUCHAR DstData, SrcData;
590     UINT DstSize, SrcSize;
591     UINT Count, Total;
592 
593     *BytesCopied = 0;
594 
595     /* Skip DestinationOffset bytes in the destination packet */
596     NdisGetFirstBufferFromPacket(Destination, &DstBuffer, (PVOID*)&DstData, &DstSize, &Total);
597     if (SkipToOffset(DstBuffer, DestinationOffset, &DstData, &DstSize) == 0xFFFFFFFF)
598         return;
599 
600     /* Skip SourceOffset bytes in the source packet */
601     NdisGetFirstBufferFromPacket(Source, &SrcBuffer, (PVOID*)&SrcData, &SrcSize, &Total);
602     if (SkipToOffset(SrcBuffer, SourceOffset, &SrcData, &SrcSize) == 0xFFFFFFFF)
603         return;
604 
605     /* Copy the data */
606     for (Total = 0;;) {
607         /* Find out how many bytes we can copy at one time */
608         if (BytesToCopy < SrcSize)
609             Count = BytesToCopy;
610         else
611             Count = SrcSize;
612         if (DstSize < Count)
613             Count = DstSize;
614 
615         RtlCopyMemory(DstData, SrcData, Count);
616 
617         Total       += Count;
618         BytesToCopy -= Count;
619         if (BytesToCopy == 0)
620             break;
621 
622         DstSize -= Count;
623         if (DstSize == 0) {
624             /* No more bytes in destination buffer. Proceed to
625                the next buffer in the destination buffer chain */
626             NdisGetNextBuffer(DstBuffer, &DstBuffer);
627             if (!DstBuffer)
628                 break;
629 
630             NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
631         }
632 
633         SrcSize -= Count;
634         if (SrcSize == 0) {
635             /* No more bytes in source buffer. Proceed to
636                the next buffer in the source buffer chain */
637             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
638             if (!SrcBuffer)
639                 break;
640 
641             NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
642         }
643     }
644 
645     *BytesCopied = Total;
646 }
647 
648 
649 /*
650  * @implemented
651  */
652 VOID
653 EXPORT
654 NdisDprAllocatePacket(
655     OUT PNDIS_STATUS    Status,
656     OUT PNDIS_PACKET    *Packet,
657     IN  NDIS_HANDLE     PoolHandle)
658 /*
659  * FUNCTION: Allocates a packet at IRQL DISPATCH_LEVEL
660  * ARGUMENTS:
661  *     Status     = Address of buffer to place status of operation
662  *     Packet     = Address of buffer to place a pointer to a packet descriptor
663  *     PoolHandle = Handle returned by NdisAllocatePacketPool
664  */
665 {
666     PNDISI_PACKET_POOL Pool = (PNDISI_PACKET_POOL)PoolHandle;
667 
668     KeAcquireSpinLockAtDpcLevel(&Pool->SpinLock.SpinLock);
669     NdisDprAllocatePacketNonInterlocked(Status,
670                                         Packet,
671                                         PoolHandle);
672     KeReleaseSpinLockFromDpcLevel(&Pool->SpinLock.SpinLock);
673 }
674 
675 
676 /*
677  * @implemented
678  */
679 VOID
680 EXPORT
681 NdisDprAllocatePacketNonInterlocked(
682     OUT PNDIS_STATUS    Status,
683     OUT PNDIS_PACKET    *Packet,
684     IN NDIS_HANDLE      PoolHandle)
685 /*
686  * FUNCTION: Allocates a packet at IRQL DISPATCH_LEVEL (w/o synchronization)
687  * ARGUMENTS:
688  *     Status     = Address of buffer to place status of operation
689  *     Packet     = Address of buffer to place a pointer to a packet descriptor
690  *     PoolHandle = Handle returned by NdisAllocatePacketPool
691  */
692 {
693     PNDIS_PACKET Temp;
694     PNDISI_PACKET_POOL Pool = (PNDISI_PACKET_POOL)PoolHandle;
695 
696     NDIS_DbgPrint(MAX_TRACE, ("Status (0x%X)  Packet (0x%X)  PoolHandle (0x%X).\n",
697         Status, Packet, PoolHandle));
698 
699     *Packet = NULL;
700 
701     if (Pool == NULL)
702     {
703         *Status = NDIS_STATUS_FAILURE;
704         NDIS_DbgPrint(MIN_TRACE, ("Called passed a bad pool handle\n"));
705         return;
706     }
707 
708     if (Pool->FreeList) {
709         Temp           = Pool->FreeList;
710         Pool->FreeList = (PNDIS_PACKET)Temp->Reserved[0];
711 
712         RtlZeroMemory(Temp, Pool->PacketLength);
713         Temp->Private.Pool = Pool;
714         Temp->Private.ValidCounts = TRUE;
715         Temp->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS;
716         Temp->Private.NdisPacketOobOffset = Pool->PacketLength -
717                                             (sizeof(NDIS_PACKET_OOB_DATA) +
718                                              sizeof(NDIS_PACKET_EXTENSION));
719 
720         *Packet = Temp;
721         *Status = NDIS_STATUS_SUCCESS;
722     } else {
723         NDIS_DbgPrint(MIN_TRACE, ("No more free descriptors\n"));
724         *Status = NDIS_STATUS_RESOURCES;
725     }
726 }
727 
728 
729 /*
730  * @implemented
731  */
732 VOID
733 EXPORT
734 NdisDprFreePacket(
735     IN  PNDIS_PACKET    Packet)
736 /*
737  * FUNCTION: Frees a packet at IRQL DISPATCH_LEVEL
738  * ARGUMENTS:
739  *     Packet = Pointer to packet to free
740  */
741 {
742     PNDISI_PACKET_POOL Pool = (PNDISI_PACKET_POOL)Packet->Private.Pool;
743 
744     KeAcquireSpinLockAtDpcLevel(&Pool->SpinLock.SpinLock);
745     NdisDprFreePacketNonInterlocked(Packet);
746     KeReleaseSpinLockFromDpcLevel(&Pool->SpinLock.SpinLock);
747 }
748 
749 
750 /*
751  * @implemented
752  */
753 VOID
754 EXPORT
755 NdisDprFreePacketNonInterlocked(
756     IN  PNDIS_PACKET    Packet)
757 /*
758  * FUNCTION: Frees a packet at IRQL DISPATCH_LEVEL (w/o synchronization)
759  * ARGUMENTS:
760  *     Packet = Pointer to packet to free
761  */
762 {
763     NDIS_DbgPrint(MAX_TRACE, ("Packet (0x%X).\n", Packet));
764 
765     Packet->Reserved[0]          = (ULONG_PTR)((NDISI_PACKET_POOL*)Packet->Private.Pool)->FreeList;
766     ((NDISI_PACKET_POOL*)Packet->Private.Pool)->FreeList = Packet;
767 }
768 
769 
770 /*
771  * @implemented
772  */
773 VOID
774 EXPORT
775 NdisFreeBufferPool(
776     IN  NDIS_HANDLE PoolHandle)
777 /*
778  * FUNCTION: Frees storage allocated for an NDIS buffer pool
779  * ARGUMENTS:
780  *     PoolHandle = Handle returned by NdisAllocateBufferPool
781  */
782 {
783 }
784 
785 
786 /*
787  * @implemented
788  */
789 VOID
790 EXPORT
791 NdisFreePacketPool(
792     IN  NDIS_HANDLE PoolHandle)
793 /*
794  * FUNCTION: Frees storage allocated for an NDIS packet pool
795  * ARGUMENTS:
796  *     PoolHandle = Handle returned by NdisAllocatePacketPool
797  */
798 {
799     ExFreePool((PVOID)PoolHandle);
800 }
801 
802 
803 /*
804  * @implemented
805  */
806 #undef NdisFreeBuffer
807 VOID
808 EXPORT
809 NdisFreeBuffer(
810     IN   PNDIS_BUFFER   Buffer)
811 /*
812  * FUNCTION: Puts an NDIS buffer descriptor back in it's pool
813  * ARGUMENTS:
814  *     Buffer = Pointer to buffer descriptor
815  */
816 {
817     IoFreeMdl(Buffer);
818 }
819 
820 
821 /*
822  * @implemented
823  */
824 VOID
825 EXPORT
826 NdisFreePacket(
827     IN   PNDIS_PACKET   Packet)
828 /*
829  * FUNCTION: Puts an NDIS packet descriptor back in it's pool
830  * ARGUMENTS:
831  *     Packet = Pointer to packet descriptor
832  */
833 {
834     PNDISI_PACKET_POOL Pool = (PNDISI_PACKET_POOL)Packet->Private.Pool;
835 
836     KeAcquireSpinLock(&Pool->SpinLock.SpinLock, &Pool->SpinLock.OldIrql);
837     NdisDprFreePacketNonInterlocked(Packet);
838     KeReleaseSpinLock(&Pool->SpinLock.SpinLock, Pool->SpinLock.OldIrql);
839 }
840 
841 
842 /*
843  * @implemented
844  */
845 #undef NdisGetBufferPhysicalArraySize
846 VOID
847 EXPORT
848 NdisGetBufferPhysicalArraySize(
849     IN  PNDIS_BUFFER    Buffer,
850     OUT PUINT           ArraySize)
851 /*
852  * FUNCTION: Returns number of discontiguous physical blocks backing a buffer
853  * ARGUMENTS:
854  *     Buffer    = Pointer to buffer descriptor
855  *     ArraySize = Address of buffer to place number of physical blocks
856  */
857 {
858   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
859   ASSERT(Buffer && ArraySize);
860 
861   *ArraySize = NDIS_BUFFER_TO_SPAN_PAGES(Buffer);
862 }
863 
864 
865 /*
866  * @implemented
867  */
868 #undef NdisGetFirstBufferFromPacket
869 VOID
870 EXPORT
871 NdisGetFirstBufferFromPacket(
872     IN  PNDIS_PACKET    _Packet,
873     OUT PNDIS_BUFFER    *_FirstBuffer,
874     OUT PVOID           *_FirstBufferVA,
875     OUT PUINT           _FirstBufferLength,
876     OUT PUINT           _TotalBufferLength)
877 /*
878  * FUNCTION: Retrieves information about an NDIS packet
879  * ARGUMENTS:
880  *     _Packet            = Pointer to NDIS packet
881  *     _FirstBuffer       = Address of buffer for pointer to first NDIS buffer
882  *     _FirstBufferVA     = Address of buffer for address of first NDIS buffer
883  *     _FirstBufferLength = Address of buffer for length of first buffer
884  *     _TotalBufferLength = Address of buffer for total length of packet
885  */
886 {
887     PNDIS_BUFFER Buffer;
888 
889     Buffer          = _Packet->Private.Head;
890     *_FirstBuffer   = Buffer;
891 
892     if (Buffer != NULL) {
893         *_FirstBufferLength = MmGetMdlByteCount(Buffer);
894         *_FirstBufferVA = MmGetSystemAddressForMdl(Buffer);
895         Buffer = Buffer->Next;
896     } else {
897         NDIS_DbgPrint(MID_TRACE, ("No buffers linked to this packet\n"));
898         *_FirstBufferLength = 0;
899         *_FirstBufferVA = NULL;
900     }
901 
902     *_TotalBufferLength = *_FirstBufferLength;
903 
904     while (Buffer != NULL) {
905         *_TotalBufferLength += MmGetMdlByteCount(Buffer);
906         Buffer = Buffer->Next;
907     }
908 }
909 
910 #undef NdisGetFirstBufferFromPacketSafe
911 /*
912  * @implemented
913  */
914 VOID
915 EXPORT
916 NdisGetFirstBufferFromPacketSafe(
917     IN  PNDIS_PACKET     _Packet,
918     OUT PNDIS_BUFFER     *_FirstBuffer,
919     OUT PVOID            *_FirstBufferVA,
920     OUT PUINT            _FirstBufferLength,
921     OUT PUINT            _TotalBufferLength,
922     IN  MM_PAGE_PRIORITY Priority)
923 {
924     PNDIS_BUFFER Buffer;
925 
926     Buffer          = _Packet->Private.Head;
927     *_FirstBuffer   = Buffer;
928 
929     if (Buffer != NULL) {
930         *_FirstBufferLength = MmGetMdlByteCount(Buffer);
931         *_FirstBufferVA = MmGetSystemAddressForMdlSafe(Buffer, Priority);
932         Buffer = Buffer->Next;
933     } else {
934         NDIS_DbgPrint(MID_TRACE, ("No buffers linked to this packet\n"));
935         *_FirstBufferLength = 0;
936         *_FirstBufferVA = NULL;
937     }
938 
939     *_TotalBufferLength = *_FirstBufferLength;
940 
941     while (Buffer != NULL) {
942         *_TotalBufferLength += MmGetMdlByteCount(Buffer);
943         Buffer = Buffer->Next;
944     }
945 }
946 
947 /*
948  * @implemented
949  */
950 #undef NdisQueryBuffer
951 VOID
952 EXPORT
953 NdisQueryBuffer(
954     IN  PNDIS_BUFFER    Buffer,
955     OUT PVOID           *VirtualAddress OPTIONAL,
956     OUT PUINT           Length)
957 /*
958  * FUNCTION:
959  *     Queries an NDIS buffer for information
960  * ARGUMENTS:
961  *     Buffer         = Pointer to NDIS buffer to query
962  *     VirtualAddress = Address of buffer to place virtual address
963  *     Length         = Address of buffer to place length of buffer
964  */
965 {
966 	if (VirtualAddress != NULL)
967 		*(PVOID*)VirtualAddress = MmGetSystemAddressForMdl(Buffer);
968 
969 	*Length = MmGetMdlByteCount(Buffer);
970 }
971 
972 
973 /*
974  * @implemented
975  */
976 #undef NdisQueryBufferSafe
977 VOID
978 EXPORT
979 NdisQueryBufferSafe(
980     IN  PNDIS_BUFFER    Buffer,
981     OUT PVOID           *VirtualAddress OPTIONAL,
982     OUT PUINT           Length,
983     IN  UINT            Priority)
984 /*
985  * FUNCTION:
986  * ARGUMENTS:
987  * NOTES:
988  *    NDIS 5.0
989  */
990 {
991     if (VirtualAddress != NULL)
992         *VirtualAddress = MmGetSystemAddressForMdlSafe(Buffer, Priority);
993     *Length = MmGetMdlByteCount(Buffer);
994 }
995 
996 
997 /*
998  * @implemented
999  */
1000 #undef NdisQueryBufferOffset
1001 VOID
1002 EXPORT
1003 NdisQueryBufferOffset(
1004     IN  PNDIS_BUFFER    Buffer,
1005     OUT PUINT           Offset,
1006     OUT PUINT           Length)
1007 {
1008     *((PUINT)Offset) = MmGetMdlByteOffset(Buffer);
1009     *((PUINT)Length) = MmGetMdlByteCount(Buffer);
1010 }
1011 
1012 
1013 /*
1014  * @implemented
1015  */
1016 VOID
1017 EXPORT
1018 NdisUnchainBufferAtBack(
1019     IN OUT  PNDIS_PACKET    Packet,
1020     OUT     PNDIS_BUFFER    *Buffer)
1021 /*
1022  * FUNCTION:
1023  *     Removes the last buffer in a packet
1024  * ARGUMENTS:
1025  *     Packet = Pointer to NDIS packet
1026  *     Buffer = Address of buffer to place pointer to removed NDIS buffer
1027  */
1028 {
1029 	PNDIS_BUFFER NdisBuffer, Previous;
1030 
1031     NdisQueryPacket(Packet,
1032                     NULL,
1033                     NULL,
1034                     &NdisBuffer,
1035                     NULL);
1036     if (!NdisBuffer) {
1037         NDIS_DbgPrint(MID_TRACE, ("No buffer to unchain\n"));
1038         *Buffer = NULL;
1039         return;
1040     }
1041 
1042     Previous = NULL;
1043     while (NdisBuffer->Next) {
1044         Previous   = NdisBuffer;
1045         NdisBuffer = NdisBuffer->Next;
1046     }
1047 
1048     if (Previous) {
1049         Previous->Next       = NULL;
1050         Packet->Private.Tail = Previous;
1051     } else {
1052         Packet->Private.Head = NULL;
1053         Packet->Private.Tail = NULL;
1054     }
1055 
1056     Packet->Private.ValidCounts = FALSE;
1057 
1058     *Buffer = NdisBuffer;
1059 }
1060 
1061 
1062 /*
1063  * @implemented
1064  */
1065 VOID
1066 EXPORT
1067 NdisUnchainBufferAtFront(
1068     IN OUT  PNDIS_PACKET    Packet,
1069     OUT     PNDIS_BUFFER    *Buffer)
1070 /*
1071  * FUNCTION:
1072  *     Removes the first buffer in a packet
1073  * ARGUMENTS:
1074  *     Packet = Pointer to NDIS packet
1075  *     Buffer = Address of buffer to place pointer to removed NDIS buffer
1076  */
1077 {
1078 	PNDIS_BUFFER NdisBuffer;
1079 
1080     NdisQueryPacket(Packet,
1081                     NULL,
1082                     NULL,
1083                     &NdisBuffer,
1084                     NULL);
1085     if (!NdisBuffer) {
1086         NDIS_DbgPrint(MID_TRACE, ("No buffer to unchain\n"));
1087         *Buffer = NULL;
1088         return;
1089     }
1090 
1091     Packet->Private.Head = NdisBuffer->Next;
1092 
1093     if (!NdisBuffer->Next)
1094         Packet->Private.Tail = NULL;
1095 
1096     NdisBuffer->Next = NULL;
1097 
1098     Packet->Private.ValidCounts = FALSE;
1099 
1100     *Buffer = NdisBuffer;
1101 }
1102 
1103 /*
1104  * @implemented
1105  */
1106 VOID
1107 EXPORT
1108 NdisCopyBuffer(
1109     OUT PNDIS_STATUS    Status,
1110     OUT PNDIS_BUFFER    *Buffer,
1111     IN  NDIS_HANDLE     PoolHandle,
1112     IN  PVOID           MemoryDescriptor,
1113     IN  UINT            Offset,
1114     IN  UINT            Length)
1115 /*
1116  * FUNCTION: Returns a new buffer descriptor for a (partial) buffer
1117  * ARGUMENTS:
1118  *     Status           = Address of a buffer to place status of operation
1119  *     Buffer           = Address of a buffer to place new buffer descriptor
1120  *     PoolHandle       = Handle returned by NdisAllocateBufferPool
1121  *     MemoryDescriptor = Pointer to a memory descriptor (possibly NDIS_BUFFER)
1122  *     Offset           = Offset in buffer to start copying
1123  *     Length           = Number of bytes to copy
1124  */
1125 {
1126     PVOID CurrentVa = (PUCHAR)(MmGetMdlVirtualAddress((PNDIS_BUFFER)MemoryDescriptor)) + Offset;
1127 
1128     NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
1129 
1130     *Buffer = IoAllocateMdl(CurrentVa, Length, FALSE, FALSE, NULL);
1131     if (!*Buffer)
1132     {
1133         NDIS_DbgPrint(MIN_TRACE, ("IoAllocateMdl failed (%x, %lx)\n", CurrentVa, Length));
1134         *Status = NDIS_STATUS_FAILURE;
1135         return;
1136     }
1137 
1138     IoBuildPartialMdl((PNDIS_BUFFER)MemoryDescriptor,
1139                       *Buffer,
1140                       CurrentVa,
1141                       Length);
1142 
1143     (*Buffer)->Next = NULL;
1144     *Status = NDIS_STATUS_SUCCESS;
1145 }
1146 
1147 /*
1148  * @implemented
1149  */
1150 NDIS_HANDLE
1151 EXPORT
1152 NdisGetPoolFromPacket(
1153     IN PNDIS_PACKET  Packet)
1154 {
1155     return Packet->Private.Pool;
1156 }
1157 
1158 /*
1159  * @implemented
1160  */
1161 UINT
1162 EXPORT
1163 NdisPacketSize(
1164     IN UINT  ProtocolReservedSize)
1165 {
1166     return sizeof(NDIS_PACKET) + sizeof(NDIS_PACKET_OOB_DATA) +
1167                  sizeof(NDIS_PACKET_EXTENSION) + ProtocolReservedSize;
1168 }
1169 
1170 /*
1171  * @implemented
1172  */
1173 #undef NdisGetPacketCancelId
1174 PVOID
1175 EXPORT
1176 NdisGetPacketCancelId(
1177     IN PNDIS_PACKET  Packet)
1178 {
1179     return NDIS_GET_PACKET_CANCEL_ID(Packet);
1180 }
1181 
1182 /*
1183  * @implemented
1184  */
1185 #undef NdisSetPacketCancelId
1186 VOID
1187 EXPORT
1188 NdisSetPacketCancelId(
1189     IN PNDIS_PACKET  Packet,
1190     IN PVOID  CancelId)
1191 {
1192     NDIS_SET_PACKET_CANCEL_ID(Packet, CancelId);
1193 }
1194 
1195 /*
1196  * @implemented
1197  */
1198 VOID
1199 EXPORT
1200 NdisCopyFromPacketToPacketSafe(
1201     IN  PNDIS_PACKET     Destination,
1202     IN  UINT             DestinationOffset,
1203     IN  UINT             BytesToCopy,
1204     IN  PNDIS_PACKET     Source,
1205     IN  UINT             SourceOffset,
1206     OUT PUINT            BytesCopied,
1207     IN  MM_PAGE_PRIORITY Priority)
1208 {
1209     PNDIS_BUFFER SrcBuffer;
1210     PNDIS_BUFFER DstBuffer;
1211     PUCHAR DstData, SrcData;
1212     UINT DstSize, SrcSize;
1213     UINT Count, Total;
1214 
1215     *BytesCopied = 0;
1216 
1217     /* Skip DestinationOffset bytes in the destination packet */
1218     NdisGetFirstBufferFromPacketSafe(Destination, &DstBuffer, (PVOID*)&DstData, &DstSize, &Total, Priority);
1219     if (!DstData || SkipToOffset(DstBuffer, DestinationOffset, &DstData, &DstSize) == 0xFFFFFFFF)
1220         return;
1221 
1222     /* Skip SourceOffset bytes in the source packet */
1223     NdisGetFirstBufferFromPacketSafe(Source, &SrcBuffer, (PVOID*)&SrcData, &SrcSize, &Total, Priority);
1224     if (!SrcData || SkipToOffset(SrcBuffer, SourceOffset, &SrcData, &SrcSize) == 0xFFFFFFFF)
1225         return;
1226 
1227     /* Copy the data */
1228     for (Total = 0;;) {
1229         /* Find out how many bytes we can copy at one time */
1230         if (BytesToCopy < SrcSize)
1231             Count = BytesToCopy;
1232         else
1233             Count = SrcSize;
1234         if (DstSize < Count)
1235             Count = DstSize;
1236 
1237         RtlCopyMemory(DstData, SrcData, Count);
1238 
1239         Total       += Count;
1240         BytesToCopy -= Count;
1241         if (BytesToCopy == 0)
1242             break;
1243 
1244         DstSize -= Count;
1245         if (DstSize == 0) {
1246             /* No more bytes in destination buffer. Proceed to
1247                the next buffer in the destination buffer chain */
1248             NdisGetNextBuffer(DstBuffer, &DstBuffer);
1249             if (!DstBuffer)
1250                 break;
1251 
1252             NdisQueryBufferSafe(DstBuffer, (PVOID)&DstData, &DstSize, Priority);
1253             if (!DstData)
1254                 break;
1255         }
1256 
1257         SrcSize -= Count;
1258         if (SrcSize == 0) {
1259             /* No more bytes in source buffer. Proceed to
1260                the next buffer in the source buffer chain */
1261             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
1262             if (!SrcBuffer)
1263                 break;
1264 
1265             NdisQueryBufferSafe(SrcBuffer, (PVOID)&SrcData, &SrcSize, Priority);
1266             if (!SrcData)
1267                 break;
1268         }
1269     }
1270 
1271     *BytesCopied = Total;
1272 }
1273 
1274 /*
1275  * @implemented
1276  */
1277 VOID
1278 EXPORT
1279 NdisIMCopySendCompletePerPacketInfo(
1280     IN  PNDIS_PACKET    DstPacket,
1281     IN  PNDIS_PACKET    SrcPacket)
1282 /*
1283  * FUNCTION:
1284  * ARGUMENTS:
1285  * NOTES:
1286  *    NDIS 5.0
1287  */
1288 {
1289     /* FIXME: What is the difference between NdisIMCopySendPerPacketInfo and
1290      * NdisIMCopySendCompletePerPacketInfo?
1291      */
1292 
1293     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1294 
1295     RtlCopyMemory(NDIS_PACKET_EXTENSION_FROM_PACKET(DstPacket),
1296                   NDIS_PACKET_EXTENSION_FROM_PACKET(SrcPacket),
1297                   sizeof(NDIS_PACKET_EXTENSION));
1298 }
1299 
1300 
1301 /*
1302  * @implemented
1303  */
1304 VOID
1305 EXPORT
1306 NdisIMCopySendPerPacketInfo(
1307     IN  PNDIS_PACKET    DstPacket,
1308     IN  PNDIS_PACKET    SrcPacket)
1309 /*
1310  * FUNCTION:
1311  * ARGUMENTS:
1312  * NOTES:
1313  *    NDIS 5.0
1314  */
1315 {
1316     /* FIXME: What is the difference between NdisIMCopySendPerPacketInfo and
1317      * NdisIMCopySendCompletePerPacketInfo?
1318      */
1319 
1320     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1321 
1322     RtlCopyMemory(NDIS_PACKET_EXTENSION_FROM_PACKET(DstPacket),
1323                   NDIS_PACKET_EXTENSION_FROM_PACKET(SrcPacket),
1324                   sizeof(NDIS_PACKET_EXTENSION));
1325 }
1326 
1327 /* EOF */
1328