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