Sync with trunk r63383 .
[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 __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 */