]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10288 6f19259b...
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / NetBuffer.c
1 /** @file
2 Network library functions providing net buffer operation support.
3
4 Copyright (c) 2005 - 2010, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13
14 #include <Uefi.h>
15
16 #include <Library/NetLib.h>
17 #include <Library/BaseLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/MemoryAllocationLib.h>
22
23
24 /**
25 Allocate and build up the sketch for a NET_BUF.
26
27 The net buffer allocated has the BlockOpNum's NET_BLOCK_OP, and its associated
28 NET_VECTOR has the BlockNum's NET_BLOCK. But all the NET_BLOCK_OP and
29 NET_BLOCK remain un-initialized.
30
31 @param[in] BlockNum The number of NET_BLOCK in the vector of net buffer
32 @param[in] BlockOpNum The number of NET_BLOCK_OP in the net buffer
33
34 @return Pointer to the allocated NET_BUF, or NULL if the
35 allocation failed due to resource limit.
36
37 **/
38 NET_BUF *
39 NetbufAllocStruct (
40 IN UINT32 BlockNum,
41 IN UINT32 BlockOpNum
42 )
43 {
44 NET_BUF *Nbuf;
45 NET_VECTOR *Vector;
46
47 ASSERT (BlockOpNum >= 1);
48
49 //
50 // Allocate three memory blocks.
51 //
52 Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));
53
54 if (Nbuf == NULL) {
55 return NULL;
56 }
57
58 Nbuf->Signature = NET_BUF_SIGNATURE;
59 Nbuf->RefCnt = 1;
60 Nbuf->BlockOpNum = BlockOpNum;
61 InitializeListHead (&Nbuf->List);
62
63 if (BlockNum != 0) {
64 Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum));
65
66 if (Vector == NULL) {
67 goto FreeNbuf;
68 }
69
70 Vector->Signature = NET_VECTOR_SIGNATURE;
71 Vector->RefCnt = 1;
72 Vector->BlockNum = BlockNum;
73 Nbuf->Vector = Vector;
74 }
75
76 return Nbuf;
77
78 FreeNbuf:
79
80 FreePool (Nbuf);
81 return NULL;
82 }
83
84
85 /**
86 Allocate a single block NET_BUF. Upon allocation, all the
87 free space is in the tail room.
88
89 @param[in] Len The length of the block.
90
91 @return Pointer to the allocated NET_BUF, or NULL if the
92 allocation failed due to resource limit.
93
94 **/
95 NET_BUF *
96 EFIAPI
97 NetbufAlloc (
98 IN UINT32 Len
99 )
100 {
101 NET_BUF *Nbuf;
102 NET_VECTOR *Vector;
103 UINT8 *Bulk;
104
105 ASSERT (Len > 0);
106
107 Nbuf = NetbufAllocStruct (1, 1);
108
109 if (Nbuf == NULL) {
110 return NULL;
111 }
112
113 Bulk = AllocatePool (Len);
114
115 if (Bulk == NULL) {
116 goto FreeNBuf;
117 }
118
119 Vector = Nbuf->Vector;
120 Vector->Len = Len;
121
122 Vector->Block[0].Bulk = Bulk;
123 Vector->Block[0].Len = Len;
124
125 Nbuf->BlockOp[0].BlockHead = Bulk;
126 Nbuf->BlockOp[0].BlockTail = Bulk + Len;
127
128 Nbuf->BlockOp[0].Head = Bulk;
129 Nbuf->BlockOp[0].Tail = Bulk;
130 Nbuf->BlockOp[0].Size = 0;
131
132 return Nbuf;
133
134 FreeNBuf:
135 FreePool (Nbuf);
136 return NULL;
137 }
138
139 /**
140 Free the net vector.
141
142 Decrease the reference count of the net vector by one. The real resource free
143 operation isn't performed until the reference count of the net vector is
144 decreased to 0.
145
146 @param[in] Vector Pointer to the NET_VECTOR to be freed.
147
148 **/
149 VOID
150 NetbufFreeVector (
151 IN NET_VECTOR *Vector
152 )
153 {
154 UINT32 Index;
155
156 ASSERT (Vector != NULL);
157 NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE);
158 ASSERT (Vector->RefCnt > 0);
159
160 Vector->RefCnt--;
161
162 if (Vector->RefCnt > 0) {
163 return;
164 }
165
166 if (Vector->Free != NULL) {
167 //
168 // Call external free function to free the vector if it
169 // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
170 // first block since it is allocated by us
171 //
172 if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {
173 gBS->FreePool (Vector->Block[0].Bulk);
174 }
175
176 Vector->Free (Vector->Arg);
177
178 } else {
179 //
180 // Free each memory block associated with the Vector
181 //
182 for (Index = 0; Index < Vector->BlockNum; Index++) {
183 gBS->FreePool (Vector->Block[Index].Bulk);
184 }
185 }
186
187 FreePool (Vector);
188 }
189
190
191 /**
192 Free the net buffer and its associated NET_VECTOR.
193
194 Decrease the reference count of the net buffer by one. Free the associated net
195 vector and itself if the reference count of the net buffer is decreased to 0.
196 The net vector free operation just decrease the reference count of the net
197 vector by one and do the real resource free operation when the reference count
198 of the net vector is 0.
199
200 @param[in] Nbuf Pointer to the NET_BUF to be freed.
201
202 **/
203 VOID
204 EFIAPI
205 NetbufFree (
206 IN NET_BUF *Nbuf
207 )
208 {
209 ASSERT (Nbuf != NULL);
210 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
211 ASSERT (Nbuf->RefCnt > 0);
212
213 Nbuf->RefCnt--;
214
215 if (Nbuf->RefCnt == 0) {
216 //
217 // Update Vector only when NBuf is to be released. That is,
218 // all the sharing of Nbuf increse Vector's RefCnt by one
219 //
220 NetbufFreeVector (Nbuf->Vector);
221 FreePool (Nbuf);
222 }
223 }
224
225
226 /**
227 Create a copy of the net buffer that shares the associated net vector.
228
229 The reference count of the newly created net buffer is set to 1. The reference
230 count of the associated net vector is increased by one.
231
232 @param[in] Nbuf Pointer to the net buffer to be cloned.
233
234 @return Pointer to the cloned net buffer, or NULL if the
235 allocation failed due to resource limit.
236
237 **/
238 NET_BUF *
239 EFIAPI
240 NetbufClone (
241 IN NET_BUF *Nbuf
242 )
243 {
244 NET_BUF *Clone;
245
246 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
247
248 Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));
249
250 if (Clone == NULL) {
251 return NULL;
252 }
253
254 Clone->Signature = NET_BUF_SIGNATURE;
255 Clone->RefCnt = 1;
256 InitializeListHead (&Clone->List);
257
258 Clone->Ip = Nbuf->Ip;
259 Clone->Tcp = Nbuf->Tcp;
260
261 CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
262
263 NET_GET_REF (Nbuf->Vector);
264
265 Clone->Vector = Nbuf->Vector;
266 Clone->BlockOpNum = Nbuf->BlockOpNum;
267 Clone->TotalSize = Nbuf->TotalSize;
268 CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);
269
270 return Clone;
271 }
272
273
274 /**
275 Create a duplicated copy of the net buffer with data copied and HeadSpace
276 bytes of head space reserved.
277
278 The duplicated net buffer will allocate its own memory to hold the data of the
279 source net buffer.
280
281 @param[in] Nbuf Pointer to the net buffer to be duplicated from.
282 @param[in, out] Duplicate Pointer to the net buffer to duplicate to, if
283 NULL a new net buffer is allocated.
284 @param[in] HeadSpace Length of the head space to reserve.
285
286 @return Pointer to the duplicated net buffer, or NULL if
287 the allocation failed due to resource limit.
288
289 **/
290 NET_BUF *
291 EFIAPI
292 NetbufDuplicate (
293 IN NET_BUF *Nbuf,
294 IN OUT NET_BUF *Duplicate OPTIONAL,
295 IN UINT32 HeadSpace
296 )
297 {
298 UINT8 *Dst;
299
300 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
301
302 if (Duplicate == NULL) {
303 Duplicate = NetbufAlloc (Nbuf->TotalSize + HeadSpace);
304 }
305
306 if (Duplicate == NULL) {
307 return NULL;
308 }
309
310 //
311 // Don't set the IP and TCP head point, since it is most
312 // like that they are pointing to the memory of Nbuf.
313 //
314 CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
315 NetbufReserve (Duplicate, HeadSpace);
316
317 Dst = NetbufAllocSpace (Duplicate, Nbuf->TotalSize, NET_BUF_TAIL);
318 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dst);
319
320 return Duplicate;
321 }
322
323
324 /**
325 Free a list of net buffers.
326
327 @param[in, out] Head Pointer to the head of linked net buffers.
328
329 **/
330 VOID
331 EFIAPI
332 NetbufFreeList (
333 IN OUT LIST_ENTRY *Head
334 )
335 {
336 LIST_ENTRY *Entry;
337 LIST_ENTRY *Next;
338 NET_BUF *Nbuf;
339
340 Entry = Head->ForwardLink;
341
342 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
343 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
344 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
345
346 RemoveEntryList (Entry);
347 NetbufFree (Nbuf);
348 }
349
350 ASSERT (IsListEmpty (Head));
351 }
352
353
354 /**
355 Get the index of NET_BLOCK_OP that contains the byte at Offset in the net
356 buffer.
357
358 This can be used to, for example, retrieve the IP header in the packet. It
359 also can be used to get the fragment that contains the byte which is used
360 mainly by the library implementation itself.
361
362 @param[in] Nbuf Pointer to the net buffer.
363 @param[in] Offset The offset of the byte.
364 @param[out] Index Index of the NET_BLOCK_OP that contains the byte at
365 Offset.
366
367 @return Pointer to the Offset'th byte of data in the net buffer, or NULL
368 if there is no such data in the net buffer.
369
370 **/
371 UINT8 *
372 EFIAPI
373 NetbufGetByte (
374 IN NET_BUF *Nbuf,
375 IN UINT32 Offset,
376 OUT UINT32 *Index OPTIONAL
377 )
378 {
379 NET_BLOCK_OP *BlockOp;
380 UINT32 Loop;
381 UINT32 Len;
382
383 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
384
385 if (Offset >= Nbuf->TotalSize) {
386 return NULL;
387 }
388
389 BlockOp = Nbuf->BlockOp;
390 Len = 0;
391
392 for (Loop = 0; Loop < Nbuf->BlockOpNum; Loop++) {
393
394 if (Len + BlockOp[Loop].Size <= Offset) {
395 Len += BlockOp[Loop].Size;
396 continue;
397 }
398
399 if (Index != NULL) {
400 *Index = Loop;
401 }
402
403 return BlockOp[Loop].Head + (Offset - Len);
404 }
405
406 return NULL;
407 }
408
409
410
411 /**
412 Set the NET_BLOCK and corresponding NET_BLOCK_OP in the net buffer and
413 corresponding net vector according to the bulk pointer and bulk length.
414
415 All the pointers in the Index'th NET_BLOCK and NET_BLOCK_OP are set to the
416 bulk's head and tail respectively. So, this function alone can't be used by
417 NetbufAlloc.
418
419 @param[in, out] Nbuf Pointer to the net buffer.
420 @param[in] Bulk Pointer to the data.
421 @param[in] Len Length of the bulk data.
422 @param[in] Index The data block index in the net buffer the bulk
423 data should belong to.
424
425 **/
426 VOID
427 NetbufSetBlock (
428 IN OUT NET_BUF *Nbuf,
429 IN UINT8 *Bulk,
430 IN UINT32 Len,
431 IN UINT32 Index
432 )
433 {
434 NET_BLOCK_OP *BlockOp;
435 NET_BLOCK *Block;
436
437 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
438 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
439 ASSERT (Index < Nbuf->BlockOpNum);
440
441 Block = &(Nbuf->Vector->Block[Index]);
442 BlockOp = &(Nbuf->BlockOp[Index]);
443 Block->Len = Len;
444 Block->Bulk = Bulk;
445 BlockOp->BlockHead = Bulk;
446 BlockOp->BlockTail = Bulk + Len;
447 BlockOp->Head = Bulk;
448 BlockOp->Tail = Bulk + Len;
449 BlockOp->Size = Len;
450 }
451
452
453
454 /**
455 Set the NET_BLOCK_OP in the net buffer. The corresponding NET_BLOCK
456 structure is left untouched.
457
458 Some times, there is no 1:1 relationship between NET_BLOCK and NET_BLOCK_OP.
459 For example, that in NetbufGetFragment.
460
461 @param[in, out] Nbuf Pointer to the net buffer.
462 @param[in] Bulk Pointer to the data.
463 @param[in] Len Length of the bulk data.
464 @param[in] Index The data block index in the net buffer the bulk
465 data should belong to.
466
467 **/
468 VOID
469 NetbufSetBlockOp (
470 IN OUT NET_BUF *Nbuf,
471 IN UINT8 *Bulk,
472 IN UINT32 Len,
473 IN UINT32 Index
474 )
475 {
476 NET_BLOCK_OP *BlockOp;
477
478 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
479 ASSERT (Index < Nbuf->BlockOpNum);
480
481 BlockOp = &(Nbuf->BlockOp[Index]);
482 BlockOp->BlockHead = Bulk;
483 BlockOp->BlockTail = Bulk + Len;
484 BlockOp->Head = Bulk;
485 BlockOp->Tail = Bulk + Len;
486 BlockOp->Size = Len;
487 }
488
489
490 /**
491 Helper function for NetbufGetFragment. NetbufGetFragment may allocate the
492 first block to reserve HeadSpace bytes header space. So it needs to create a
493 new net vector for the first block and can avoid copy for the remaining data
494 by sharing the old net vector.
495
496 @param[in] Arg Point to the old NET_VECTOR.
497
498 **/
499 VOID
500 NetbufGetFragmentFree (
501 IN VOID *Arg
502 )
503 {
504 NET_VECTOR *Vector;
505
506 Vector = (NET_VECTOR *)Arg;
507 NetbufFreeVector (Vector);
508 }
509
510
511 /**
512 Create a NET_BUF structure which contains Len byte data of Nbuf starting from
513 Offset.
514
515 A new NET_BUF structure will be created but the associated data in NET_VECTOR
516 is shared. This function exists to do IP packet fragmentation.
517
518 @param[in] Nbuf Pointer to the net buffer to be extracted.
519 @param[in] Offset Starting point of the data to be included in the new
520 net buffer.
521 @param[in] Len Bytes of data to be included in the new net buffer.
522 @param[in] HeadSpace Bytes of head space to reserve for protocol header.
523
524 @return Pointer to the cloned net buffer, or NULL if the
525 allocation failed due to resource limit.
526
527 **/
528 NET_BUF *
529 EFIAPI
530 NetbufGetFragment (
531 IN NET_BUF *Nbuf,
532 IN UINT32 Offset,
533 IN UINT32 Len,
534 IN UINT32 HeadSpace
535 )
536 {
537 NET_BUF *Child;
538 NET_VECTOR *Vector;
539 NET_BLOCK_OP *BlockOp;
540 UINT32 CurBlockOp;
541 UINT32 BlockOpNum;
542 UINT8 *FirstBulk;
543 UINT32 Index;
544 UINT32 First;
545 UINT32 Last;
546 UINT32 FirstSkip;
547 UINT32 FirstLen;
548 UINT32 LastLen;
549 UINT32 Cur;
550
551 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
552
553 if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {
554 return NULL;
555 }
556
557 //
558 // First find the first and last BlockOp that contains
559 // the valid data, and compute the offset of the first
560 // BlockOp and length of the last BlockOp
561 //
562 BlockOp = Nbuf->BlockOp;
563 Cur = 0;
564
565 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
566 if (Offset < Cur + BlockOp[Index].Size) {
567 break;
568 }
569
570 Cur += BlockOp[Index].Size;
571 }
572
573 //
574 // First is the index of the first BlockOp, FirstSkip is
575 // the offset of the first byte in the first BlockOp.
576 //
577 First = Index;
578 FirstSkip = Offset - Cur;
579 FirstLen = BlockOp[Index].Size - FirstSkip;
580
581 Last = 0;
582 LastLen = 0;
583
584 if (Len > FirstLen) {
585 Cur += BlockOp[Index].Size;
586 Index++;
587
588 for (; Index < Nbuf->BlockOpNum; Index++) {
589 if (Offset + Len <= Cur + BlockOp[Index].Size) {
590 Last = Index;
591 LastLen = Offset + Len - Cur;
592 break;
593 }
594
595 Cur += BlockOp[Index].Size;
596 }
597
598 } else {
599 Last = First;
600 LastLen = Len;
601 FirstLen = Len;
602 }
603
604 ASSERT (Last >= First);
605 BlockOpNum = Last - First + 1;
606 CurBlockOp = 0;
607
608 if (HeadSpace != 0) {
609 //
610 // Allocate an extra block to accomdate the head space.
611 //
612 BlockOpNum++;
613
614 Child = NetbufAllocStruct (1, BlockOpNum);
615
616 if (Child == NULL) {
617 return NULL;
618 }
619
620 FirstBulk = AllocatePool (HeadSpace);
621
622 if (FirstBulk == NULL) {
623 goto FreeChild;
624 }
625
626 Vector = Child->Vector;
627 Vector->Free = NetbufGetFragmentFree;
628 Vector->Arg = Nbuf->Vector;
629 Vector->Flag = NET_VECTOR_OWN_FIRST;
630 Vector->Len = HeadSpace;
631
632 //
633 // Reserve the head space in the first block
634 //
635 NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);
636 Child->BlockOp[0].Head += HeadSpace;
637 Child->BlockOp[0].Size = 0;
638 CurBlockOp++;
639
640 } else {
641 Child = NetbufAllocStruct (0, BlockOpNum);
642
643 if (Child == NULL) {
644 return NULL;
645 }
646
647 Child->Vector = Nbuf->Vector;
648 }
649
650 NET_GET_REF (Nbuf->Vector);
651 Child->TotalSize = Len;
652
653 //
654 // Set all the BlockOp up, the first and last one are special
655 // and need special process.
656 //
657 NetbufSetBlockOp (
658 Child,
659 Nbuf->BlockOp[First].Head + FirstSkip,
660 FirstLen,
661 CurBlockOp++
662 );
663
664 for (Index = First + 1; Index < Last; Index++) {
665 NetbufSetBlockOp (
666 Child,
667 BlockOp[Index].Head,
668 BlockOp[Index].Size,
669 CurBlockOp++
670 );
671 }
672
673 if (First != Last) {
674 NetbufSetBlockOp (
675 Child,
676 BlockOp[Last].Head,
677 LastLen,
678 CurBlockOp
679 );
680 }
681
682 CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
683 return Child;
684
685 FreeChild:
686
687 FreePool (Child);
688 return NULL;
689 }
690
691
692
693 /**
694 Build a NET_BUF from external blocks.
695
696 A new NET_BUF structure will be created from external blocks. Additional block
697 of memory will be allocated to hold reserved HeadSpace bytes of header room
698 and existing HeadLen bytes of header but the external blocks are shared by the
699 net buffer to avoid data copying.
700
701 @param[in] ExtFragment Pointer to the data block.
702 @param[in] ExtNum The number of the data blocks.
703 @param[in] HeadSpace The head space to be reserved.
704 @param[in] HeadLen The length of the protocol header, This function
705 will pull that number of data into a linear block.
706 @param[in] ExtFree Pointer to the caller provided free function.
707 @param[in] Arg The argument passed to ExtFree when ExtFree is
708 called.
709
710 @return Pointer to the net buffer built from the data blocks,
711 or NULL if the allocation failed due to resource
712 limit.
713
714 **/
715 NET_BUF *
716 EFIAPI
717 NetbufFromExt (
718 IN NET_FRAGMENT *ExtFragment,
719 IN UINT32 ExtNum,
720 IN UINT32 HeadSpace,
721 IN UINT32 HeadLen,
722 IN NET_VECTOR_EXT_FREE ExtFree,
723 IN VOID *Arg OPTIONAL
724 )
725 {
726 NET_BUF *Nbuf;
727 NET_VECTOR *Vector;
728 NET_FRAGMENT SavedFragment;
729 UINT32 SavedIndex;
730 UINT32 TotalLen;
731 UINT32 BlockNum;
732 UINT8 *FirstBlock;
733 UINT32 FirstBlockLen;
734 UINT8 *Header;
735 UINT32 CurBlock;
736 UINT32 Index;
737 UINT32 Len;
738 UINT32 Copied;
739
740 ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));
741
742 SavedFragment.Bulk = NULL;
743 SavedFragment.Len = 0;
744
745 FirstBlockLen = 0;
746 FirstBlock = NULL;
747 BlockNum = ExtNum;
748 Index = 0;
749 TotalLen = 0;
750 SavedIndex = 0;
751 Len = 0;
752 Copied = 0;
753
754 //
755 // No need to consolidate the header if the first block is
756 // longer than the header length or there is only one block.
757 //
758 if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {
759 HeadLen = 0;
760 }
761
762 //
763 // Allocate an extra block if we need to:
764 // 1. Allocate some header space
765 // 2. aggreate the packet header
766 //
767 if ((HeadSpace != 0) || (HeadLen != 0)) {
768 FirstBlockLen = HeadLen + HeadSpace;
769 FirstBlock = AllocatePool (FirstBlockLen);
770
771 if (FirstBlock == NULL) {
772 return NULL;
773 }
774
775 BlockNum++;
776 }
777
778 //
779 // Copy the header to the first block, reduce the NET_BLOCK
780 // to allocate by one for each block that is completely covered
781 // by the first bulk.
782 //
783 if (HeadLen != 0) {
784 Len = HeadLen;
785 Header = FirstBlock + HeadSpace;
786
787 for (Index = 0; Index < ExtNum; Index++) {
788 if (Len >= ExtFragment[Index].Len) {
789 CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);
790
791 Copied += ExtFragment[Index].Len;
792 Len -= ExtFragment[Index].Len;
793 Header += ExtFragment[Index].Len;
794 TotalLen += ExtFragment[Index].Len;
795 BlockNum--;
796
797 if (Len == 0) {
798 //
799 // Increament the index number to point to the next
800 // non-empty fragment.
801 //
802 Index++;
803 break;
804 }
805
806 } else {
807 CopyMem (Header, ExtFragment[Index].Bulk, Len);
808
809 Copied += Len;
810 TotalLen += Len;
811
812 //
813 // Adjust the block structure to exclude the data copied,
814 // So, the left-over block can be processed as other blocks.
815 // But it must be recovered later. (SavedIndex > 0) always
816 // holds since we don't aggreate the header if the first block
817 // is bigger enough that the header is continuous
818 //
819 SavedIndex = Index;
820 SavedFragment = ExtFragment[Index];
821 ExtFragment[Index].Bulk += Len;
822 ExtFragment[Index].Len -= Len;
823 break;
824 }
825 }
826 }
827
828 Nbuf = NetbufAllocStruct (BlockNum, BlockNum);
829
830 if (Nbuf == NULL) {
831 goto FreeFirstBlock;
832 }
833
834 Vector = Nbuf->Vector;
835 Vector->Free = ExtFree;
836 Vector->Arg = Arg;
837 Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);
838
839 //
840 // Set the first block up which may contain
841 // some head space and aggregated header
842 //
843 CurBlock = 0;
844
845 if (FirstBlockLen != 0) {
846 NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);
847 Nbuf->BlockOp[0].Head += HeadSpace;
848 Nbuf->BlockOp[0].Size = Copied;
849
850 CurBlock++;
851 }
852
853 for (; Index < ExtNum; Index++) {
854 NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);
855 TotalLen += ExtFragment[Index].Len;
856 CurBlock++;
857 }
858
859 Vector->Len = TotalLen + HeadSpace;
860 Nbuf->TotalSize = TotalLen;
861
862 if (SavedIndex != 0) {
863 ExtFragment[SavedIndex] = SavedFragment;
864 }
865
866 return Nbuf;
867
868 FreeFirstBlock:
869 if (FirstBlock != NULL) {
870 FreePool (FirstBlock);
871 }
872 return NULL;
873 }
874
875
876 /**
877 Build a fragment table to contain the fragments in the net buffer. This is the
878 opposite operation of the NetbufFromExt.
879
880 @param[in] Nbuf Point to the net buffer.
881 @param[in, out] ExtFragment Pointer to the data block.
882 @param[in, out] ExtNum The number of the data blocks.
883
884 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than
885 ExtNum.
886 @retval EFI_SUCCESS Fragment table is built successfully.
887
888 **/
889 EFI_STATUS
890 EFIAPI
891 NetbufBuildExt (
892 IN NET_BUF *Nbuf,
893 IN OUT NET_FRAGMENT *ExtFragment,
894 IN OUT UINT32 *ExtNum
895 )
896 {
897 UINT32 Index;
898 UINT32 Current;
899
900 Current = 0;
901
902 for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {
903 if (Nbuf->BlockOp[Index].Size == 0) {
904 continue;
905 }
906
907 if (Current < *ExtNum) {
908 ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
909 ExtFragment[Current].Len = Nbuf->BlockOp[Index].Size;
910 Current++;
911 } else {
912 return EFI_BUFFER_TOO_SMALL;
913 }
914 }
915
916 *ExtNum = Current;
917 return EFI_SUCCESS;
918 }
919
920
921 /**
922 Build a net buffer from a list of net buffers.
923
924 All the fragments will be collected from the list of NEW_BUF and then a new
925 net buffer will be created through NetbufFromExt.
926
927 @param[in] BufList A List of the net buffer.
928 @param[in] HeadSpace The head space to be reserved.
929 @param[in] HeaderLen The length of the protocol header, This function
930 will pull that number of data into a linear block.
931 @param[in] ExtFree Pointer to the caller provided free function.
932 @param[in] Arg The argument passed to ExtFree when ExtFree is called.
933
934 @return Pointer to the net buffer built from the list of net
935 buffers.
936
937 **/
938 NET_BUF *
939 EFIAPI
940 NetbufFromBufList (
941 IN LIST_ENTRY *BufList,
942 IN UINT32 HeadSpace,
943 IN UINT32 HeaderLen,
944 IN NET_VECTOR_EXT_FREE ExtFree,
945 IN VOID *Arg OPTIONAL
946 )
947 {
948 NET_FRAGMENT *Fragment;
949 UINT32 FragmentNum;
950 LIST_ENTRY *Entry;
951 NET_BUF *Nbuf;
952 UINT32 Index;
953 UINT32 Current;
954
955 //
956 //Compute how many blocks are there
957 //
958 FragmentNum = 0;
959
960 NET_LIST_FOR_EACH (Entry, BufList) {
961 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
962 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
963 FragmentNum += Nbuf->BlockOpNum;
964 }
965
966 //
967 //Allocate and copy block points
968 //
969 Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);
970
971 if (Fragment == NULL) {
972 return NULL;
973 }
974
975 Current = 0;
976
977 NET_LIST_FOR_EACH (Entry, BufList) {
978 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
979 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
980
981 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
982 if (Nbuf->BlockOp[Index].Size != 0) {
983 Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
984 Fragment[Current].Len = Nbuf->BlockOp[Index].Size;
985 Current++;
986 }
987 }
988 }
989
990 Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);
991 FreePool (Fragment);
992
993 return Nbuf;
994 }
995
996
997 /**
998 Reserve some space in the header room of the net buffer.
999
1000 Upon allocation, all the space are in the tail room of the buffer. Call this
1001 function to move some space to the header room. This function is quite limited
1002 in that it can only reserve space from the first block of an empty NET_BUF not
1003 built from the external. But it should be enough for the network stack.
1004
1005 @param[in, out] Nbuf Pointer to the net buffer.
1006 @param[in] Len The length of buffer to be reserved from the header.
1007
1008 **/
1009 VOID
1010 EFIAPI
1011 NetbufReserve (
1012 IN OUT NET_BUF *Nbuf,
1013 IN UINT32 Len
1014 )
1015 {
1016 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1017 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
1018
1019 ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));
1020 ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));
1021
1022 Nbuf->BlockOp[0].Head += Len;
1023 Nbuf->BlockOp[0].Tail += Len;
1024
1025 ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);
1026 }
1027
1028
1029 /**
1030 Allocate Len bytes of space from the header or tail of the buffer.
1031
1032 @param[in, out] Nbuf Pointer to the net buffer.
1033 @param[in] Len The length of the buffer to be allocated.
1034 @param[in] FromHead The flag to indicate whether reserve the data
1035 from head (TRUE) or tail (FALSE).
1036
1037 @return Pointer to the first byte of the allocated buffer,
1038 or NULL if there is no sufficient space.
1039
1040 **/
1041 UINT8*
1042 EFIAPI
1043 NetbufAllocSpace (
1044 IN OUT NET_BUF *Nbuf,
1045 IN UINT32 Len,
1046 IN BOOLEAN FromHead
1047 )
1048 {
1049 NET_BLOCK_OP *BlockOp;
1050 UINT32 Index;
1051 UINT8 *SavedTail;
1052
1053 Index = 0;
1054
1055 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1056 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
1057
1058 ASSERT (Len > 0);
1059
1060 if (FromHead) {
1061 //
1062 // Allocate some space from head. If the buffer is empty,
1063 // allocate from the first block. If it isn't, allocate
1064 // from the first non-empty block, or the block before that.
1065 //
1066 if (Nbuf->TotalSize == 0) {
1067 Index = 0;
1068 } else {
1069 NetbufGetByte (Nbuf, 0, &Index);
1070
1071 if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
1072 Index--;
1073 }
1074 }
1075
1076 BlockOp = &(Nbuf->BlockOp[Index]);
1077
1078 if (NET_HEADSPACE (BlockOp) < Len) {
1079 return NULL;
1080 }
1081
1082 BlockOp->Head -= Len;
1083 BlockOp->Size += Len;
1084 Nbuf->TotalSize += Len;
1085
1086 return BlockOp->Head;
1087
1088 } else {
1089 //
1090 // Allocate some space from the tail. If the buffer is empty,
1091 // allocate from the first block. If it isn't, allocate
1092 // from the last non-empty block, or the block after that.
1093 //
1094 if (Nbuf->TotalSize == 0) {
1095 Index = 0;
1096 } else {
1097 NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
1098
1099 if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
1100 (Index < Nbuf->BlockOpNum - 1)) {
1101
1102 Index++;
1103 }
1104 }
1105
1106 BlockOp = &(Nbuf->BlockOp[Index]);
1107
1108 if (NET_TAILSPACE (BlockOp) < Len) {
1109 return NULL;
1110 }
1111
1112 SavedTail = BlockOp->Tail;
1113
1114 BlockOp->Tail += Len;
1115 BlockOp->Size += Len;
1116 Nbuf->TotalSize += Len;
1117
1118 return SavedTail;
1119 }
1120 }
1121
1122
1123 /**
1124 Trim a single NET_BLOCK by Len bytes from the header or tail.
1125
1126 @param[in, out] BlockOp Pointer to the NET_BLOCK.
1127 @param[in] Len The length of the data to be trimmed.
1128 @param[in] FromHead The flag to indicate whether trim data from head
1129 (TRUE) or tail (FALSE).
1130
1131 **/
1132 VOID
1133 NetblockTrim (
1134 IN OUT NET_BLOCK_OP *BlockOp,
1135 IN UINT32 Len,
1136 IN BOOLEAN FromHead
1137 )
1138 {
1139 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));
1140
1141 BlockOp->Size -= Len;
1142
1143 if (FromHead) {
1144 BlockOp->Head += Len;
1145 } else {
1146 BlockOp->Tail -= Len;
1147 }
1148 }
1149
1150
1151 /**
1152 Trim Len bytes from the header or tail of the net buffer.
1153
1154 @param[in, out] Nbuf Pointer to the net buffer.
1155 @param[in] Len The length of the data to be trimmed.
1156 @param[in] FromHead The flag to indicate whether trim data from head
1157 (TRUE) or tail (FALSE).
1158
1159 @return Length of the actually trimmed data, which is possible to be less
1160 than Len because the TotalSize of Nbuf is less than Len.
1161
1162 **/
1163 UINT32
1164 EFIAPI
1165 NetbufTrim (
1166 IN OUT NET_BUF *Nbuf,
1167 IN UINT32 Len,
1168 IN BOOLEAN FromHead
1169 )
1170 {
1171 NET_BLOCK_OP *BlockOp;
1172 UINT32 Index;
1173 UINT32 Trimmed;
1174
1175 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1176
1177 if (Len > Nbuf->TotalSize) {
1178 Len = Nbuf->TotalSize;
1179 }
1180
1181 //
1182 // If FromTail is true, iterate backward. That
1183 // is, init Index to NBuf->BlockNum - 1, and
1184 // decrease it by 1 during each loop. Otherwise,
1185 // iterate forward. That is, init Index to 0, and
1186 // increase it by 1 during each loop.
1187 //
1188 Trimmed = 0;
1189 Nbuf->TotalSize -= Len;
1190
1191 Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
1192 BlockOp = Nbuf->BlockOp;
1193
1194 for (;;) {
1195 if (BlockOp[Index].Size == 0) {
1196 Index += (FromHead ? 1 : -1);
1197 continue;
1198 }
1199
1200 if (Len > BlockOp[Index].Size) {
1201 Len -= BlockOp[Index].Size;
1202 Trimmed += BlockOp[Index].Size;
1203 NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
1204 } else {
1205 Trimmed += Len;
1206 NetblockTrim (&BlockOp[Index], Len, FromHead);
1207 break;
1208 }
1209
1210 Index += (FromHead ? 1 : -1);
1211 }
1212
1213 return Trimmed;
1214 }
1215
1216
1217 /**
1218 Copy Len bytes of data from the specific offset of the net buffer to the
1219 destination memory.
1220
1221 The Len bytes of data may cross the several fragments of the net buffer.
1222
1223 @param[in] Nbuf Pointer to the net buffer.
1224 @param[in] Offset The sequence number of the first byte to copy.
1225 @param[in] Len Length of the data to copy.
1226 @param[in] Dest The destination of the data to copy to.
1227
1228 @return The length of the actual copied data, or 0 if the offset
1229 specified exceeds the total size of net buffer.
1230
1231 **/
1232 UINT32
1233 EFIAPI
1234 NetbufCopy (
1235 IN NET_BUF *Nbuf,
1236 IN UINT32 Offset,
1237 IN UINT32 Len,
1238 IN UINT8 *Dest
1239 )
1240 {
1241 NET_BLOCK_OP *BlockOp;
1242 UINT32 Skip;
1243 UINT32 Left;
1244 UINT32 Copied;
1245 UINT32 Index;
1246 UINT32 Cur;
1247
1248 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1249 ASSERT (Dest);
1250
1251 if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
1252 return 0;
1253 }
1254
1255 if (Nbuf->TotalSize - Offset < Len) {
1256 Len = Nbuf->TotalSize - Offset;
1257 }
1258
1259 BlockOp = Nbuf->BlockOp;
1260
1261 //
1262 // Skip to the offset. Don't make "Offset-By-One" error here.
1263 // Cur + BLOCK.SIZE is the first sequence number of next block.
1264 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
1265 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
1266 // first byte is the next block's first byte.
1267 //
1268 Cur = 0;
1269
1270 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1271 if (BlockOp[Index].Size == 0) {
1272 continue;
1273 }
1274
1275 if (Offset < Cur + BlockOp[Index].Size) {
1276 break;
1277 }
1278
1279 Cur += BlockOp[Index].Size;
1280 }
1281
1282 //
1283 // Cur is the sequence number of the first byte in the block
1284 // Offset - Cur is the number of bytes before first byte to
1285 // to copy in the current block.
1286 //
1287 Skip = Offset - Cur;
1288 Left = BlockOp[Index].Size - Skip;
1289
1290 if (Len <= Left) {
1291 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);
1292 return Len;
1293 }
1294
1295 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);
1296
1297 Dest += Left;
1298 Len -= Left;
1299 Copied = Left;
1300
1301 Index++;
1302
1303 for (; Index < Nbuf->BlockOpNum; Index++) {
1304 if (Len > BlockOp[Index].Size) {
1305 Len -= BlockOp[Index].Size;
1306 Copied += BlockOp[Index].Size;
1307
1308 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
1309 Dest += BlockOp[Index].Size;
1310 } else {
1311 Copied += Len;
1312 CopyMem (Dest, BlockOp[Index].Head, Len);
1313 break;
1314 }
1315 }
1316
1317 return Copied;
1318 }
1319
1320
1321 /**
1322 Initiate the net buffer queue.
1323
1324 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.
1325
1326 **/
1327 VOID
1328 EFIAPI
1329 NetbufQueInit (
1330 IN OUT NET_BUF_QUEUE *NbufQue
1331 )
1332 {
1333 NbufQue->Signature = NET_QUE_SIGNATURE;
1334 NbufQue->RefCnt = 1;
1335 InitializeListHead (&NbufQue->List);
1336
1337 InitializeListHead (&NbufQue->BufList);
1338 NbufQue->BufSize = 0;
1339 NbufQue->BufNum = 0;
1340 }
1341
1342
1343 /**
1344 Allocate and initialize a net buffer queue.
1345
1346 @return Pointer to the allocated net buffer queue, or NULL if the
1347 allocation failed due to resource limit.
1348
1349 **/
1350 NET_BUF_QUEUE *
1351 EFIAPI
1352 NetbufQueAlloc (
1353 VOID
1354 )
1355 {
1356 NET_BUF_QUEUE *NbufQue;
1357
1358 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));
1359 if (NbufQue == NULL) {
1360 return NULL;
1361 }
1362
1363 NetbufQueInit (NbufQue);
1364
1365 return NbufQue;
1366 }
1367
1368
1369 /**
1370 Free a net buffer queue.
1371
1372 Decrease the reference count of the net buffer queue by one. The real resource
1373 free operation isn't performed until the reference count of the net buffer
1374 queue is decreased to 0.
1375
1376 @param[in] NbufQue Pointer to the net buffer queue to be freed.
1377
1378 **/
1379 VOID
1380 EFIAPI
1381 NetbufQueFree (
1382 IN NET_BUF_QUEUE *NbufQue
1383 )
1384 {
1385 ASSERT (NbufQue != NULL);
1386 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1387
1388 NbufQue->RefCnt--;
1389
1390 if (NbufQue->RefCnt == 0) {
1391 NetbufQueFlush (NbufQue);
1392 FreePool (NbufQue);
1393 }
1394 }
1395
1396
1397 /**
1398 Append a net buffer to the net buffer queue.
1399
1400 @param[in, out] NbufQue Pointer to the net buffer queue.
1401 @param[in, out] Nbuf Pointer to the net buffer to be appended.
1402
1403 **/
1404 VOID
1405 EFIAPI
1406 NetbufQueAppend (
1407 IN OUT NET_BUF_QUEUE *NbufQue,
1408 IN OUT NET_BUF *Nbuf
1409 )
1410 {
1411 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1412 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1413
1414 InsertTailList (&NbufQue->BufList, &Nbuf->List);
1415
1416 NbufQue->BufSize += Nbuf->TotalSize;
1417 NbufQue->BufNum++;
1418 }
1419
1420
1421 /**
1422 Remove a net buffer from the head in the specific queue and return it.
1423
1424 @param[in, out] NbufQue Pointer to the net buffer queue.
1425
1426 @return Pointer to the net buffer removed from the specific queue,
1427 or NULL if there is no net buffer in the specific queue.
1428
1429 **/
1430 NET_BUF *
1431 EFIAPI
1432 NetbufQueRemove (
1433 IN OUT NET_BUF_QUEUE *NbufQue
1434 )
1435 {
1436 NET_BUF *First;
1437
1438 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1439
1440 if (NbufQue->BufNum == 0) {
1441 return NULL;
1442 }
1443
1444 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
1445
1446 NetListRemoveHead (&NbufQue->BufList);
1447
1448 NbufQue->BufSize -= First->TotalSize;
1449 NbufQue->BufNum--;
1450 return First;
1451 }
1452
1453
1454 /**
1455 Copy Len bytes of data from the net buffer queue at the specific offset to the
1456 destination memory.
1457
1458 The copying operation is the same as NetbufCopy but applies to the net buffer
1459 queue instead of the net buffer.
1460
1461 @param[in] NbufQue Pointer to the net buffer queue.
1462 @param[in] Offset The sequence number of the first byte to copy.
1463 @param[in] Len Length of the data to copy.
1464 @param[out] Dest The destination of the data to copy to.
1465
1466 @return The length of the actual copied data, or 0 if the offset
1467 specified exceeds the total size of net buffer queue.
1468
1469 **/
1470 UINT32
1471 EFIAPI
1472 NetbufQueCopy (
1473 IN NET_BUF_QUEUE *NbufQue,
1474 IN UINT32 Offset,
1475 IN UINT32 Len,
1476 OUT UINT8 *Dest
1477 )
1478 {
1479 LIST_ENTRY *Entry;
1480 NET_BUF *Nbuf;
1481 UINT32 Skip;
1482 UINT32 Left;
1483 UINT32 Cur;
1484 UINT32 Copied;
1485
1486 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1487 ASSERT (Dest != NULL);
1488
1489 if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
1490 return 0;
1491 }
1492
1493 if (NbufQue->BufSize - Offset < Len) {
1494 Len = NbufQue->BufSize - Offset;
1495 }
1496
1497 //
1498 // skip to the Offset
1499 //
1500 Cur = 0;
1501 Nbuf = NULL;
1502
1503 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
1504 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1505
1506 if (Offset < Cur + Nbuf->TotalSize) {
1507 break;
1508 }
1509
1510 Cur += Nbuf->TotalSize;
1511 }
1512
1513 ASSERT (Nbuf != NULL);
1514
1515 //
1516 // Copy the data in the first buffer.
1517 //
1518 Skip = Offset - Cur;
1519 Left = Nbuf->TotalSize - Skip;
1520
1521 if (Len < Left) {
1522 return NetbufCopy (Nbuf, Skip, Len, Dest);
1523 }
1524
1525 NetbufCopy (Nbuf, Skip, Left, Dest);
1526 Dest += Left;
1527 Len -= Left;
1528 Copied = Left;
1529
1530 //
1531 // Iterate over the others
1532 //
1533 Entry = Entry->ForwardLink;
1534
1535 while ((Len > 0) && (Entry != &NbufQue->BufList)) {
1536 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1537
1538 if (Len > Nbuf->TotalSize) {
1539 Len -= Nbuf->TotalSize;
1540 Copied += Nbuf->TotalSize;
1541
1542 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
1543 Dest += Nbuf->TotalSize;
1544
1545 } else {
1546 NetbufCopy (Nbuf, 0, Len, Dest);
1547 Copied += Len;
1548 break;
1549 }
1550
1551 Entry = Entry->ForwardLink;
1552 }
1553
1554 return Copied;
1555 }
1556
1557
1558 /**
1559 Trim Len bytes of data from the buffer queue and free any net buffer
1560 that is completely trimmed.
1561
1562 The trimming operation is the same as NetbufTrim but applies to the net buffer
1563 queue instead of the net buffer.
1564
1565 @param[in, out] NbufQue Pointer to the net buffer queue.
1566 @param[in] Len Length of the data to trim.
1567
1568 @return The actual length of the data trimmed.
1569
1570 **/
1571 UINT32
1572 EFIAPI
1573 NetbufQueTrim (
1574 IN OUT NET_BUF_QUEUE *NbufQue,
1575 IN UINT32 Len
1576 )
1577 {
1578 LIST_ENTRY *Entry;
1579 LIST_ENTRY *Next;
1580 NET_BUF *Nbuf;
1581 UINT32 Trimmed;
1582
1583 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1584
1585 if (Len == 0) {
1586 return 0;
1587 }
1588
1589 if (Len > NbufQue->BufSize) {
1590 Len = NbufQue->BufSize;
1591 }
1592
1593 NbufQue->BufSize -= Len;
1594 Trimmed = 0;
1595
1596 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
1597 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1598
1599 if (Len >= Nbuf->TotalSize) {
1600 Trimmed += Nbuf->TotalSize;
1601 Len -= Nbuf->TotalSize;
1602
1603 RemoveEntryList (Entry);
1604 NetbufFree (Nbuf);
1605
1606 NbufQue->BufNum--;
1607
1608 if (Len == 0) {
1609 break;
1610 }
1611
1612 } else {
1613 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
1614 break;
1615 }
1616 }
1617
1618 return Trimmed;
1619 }
1620
1621
1622 /**
1623 Flush the net buffer queue.
1624
1625 @param[in, out] NbufQue Pointer to the queue to be flushed.
1626
1627 **/
1628 VOID
1629 EFIAPI
1630 NetbufQueFlush (
1631 IN OUT NET_BUF_QUEUE *NbufQue
1632 )
1633 {
1634 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1635
1636 NetbufFreeList (&NbufQue->BufList);
1637
1638 NbufQue->BufNum = 0;
1639 NbufQue->BufSize = 0;
1640 }
1641
1642
1643 /**
1644 Compute the checksum for a bulk of data.
1645
1646 @param[in] Bulk Pointer to the data.
1647 @param[in] Len Length of the data, in bytes.
1648
1649 @return The computed checksum.
1650
1651 **/
1652 UINT16
1653 EFIAPI
1654 NetblockChecksum (
1655 IN UINT8 *Bulk,
1656 IN UINT32 Len
1657 )
1658 {
1659 register UINT32 Sum;
1660
1661 Sum = 0;
1662
1663 while (Len > 1) {
1664 Sum += *(UINT16 *) Bulk;
1665 Bulk += 2;
1666 Len -= 2;
1667 }
1668
1669 //
1670 // Add left-over byte, if any
1671 //
1672 if (Len > 0) {
1673 Sum += *(UINT8 *) Bulk;
1674 }
1675
1676 //
1677 // Fold 32-bit sum to 16 bits
1678 //
1679 while ((Sum >> 16) != 0) {
1680 Sum = (Sum & 0xffff) + (Sum >> 16);
1681
1682 }
1683
1684 return (UINT16) Sum;
1685 }
1686
1687
1688 /**
1689 Add two checksums.
1690
1691 @param[in] Checksum1 The first checksum to be added.
1692 @param[in] Checksum2 The second checksum to be added.
1693
1694 @return The new checksum.
1695
1696 **/
1697 UINT16
1698 EFIAPI
1699 NetAddChecksum (
1700 IN UINT16 Checksum1,
1701 IN UINT16 Checksum2
1702 )
1703 {
1704 UINT32 Sum;
1705
1706 Sum = Checksum1 + Checksum2;
1707
1708 //
1709 // two UINT16 can only add up to a carry of 1.
1710 //
1711 if ((Sum >> 16) != 0) {
1712 Sum = (Sum & 0xffff) + 1;
1713
1714 }
1715
1716 return (UINT16) Sum;
1717 }
1718
1719
1720 /**
1721 Compute the checksum for a NET_BUF.
1722
1723 @param[in] Nbuf Pointer to the net buffer.
1724
1725 @return The computed checksum.
1726
1727 **/
1728 UINT16
1729 EFIAPI
1730 NetbufChecksum (
1731 IN NET_BUF *Nbuf
1732 )
1733 {
1734 NET_BLOCK_OP *BlockOp;
1735 UINT32 Offset;
1736 UINT16 TotalSum;
1737 UINT16 BlockSum;
1738 UINT32 Index;
1739
1740 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1741
1742 TotalSum = 0;
1743 Offset = 0;
1744 BlockOp = Nbuf->BlockOp;
1745
1746 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1747 if (BlockOp[Index].Size == 0) {
1748 continue;
1749 }
1750
1751 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
1752
1753 if ((Offset & 0x01) != 0) {
1754 //
1755 // The checksum starts with an odd byte, swap
1756 // the checksum before added to total checksum
1757 //
1758 BlockSum = SwapBytes16 (BlockSum);
1759 }
1760
1761 TotalSum = NetAddChecksum (BlockSum, TotalSum);
1762 Offset += BlockOp[Index].Size;
1763 }
1764
1765 return TotalSum;
1766 }
1767
1768
1769 /**
1770 Compute the checksum for TCP/UDP pseudo header.
1771
1772 Src and Dst are in network byte order, and Len is in host byte order.
1773
1774 @param[in] Src The source address of the packet.
1775 @param[in] Dst The destination address of the packet.
1776 @param[in] Proto The protocol type of the packet.
1777 @param[in] Len The length of the packet.
1778
1779 @return The computed checksum.
1780
1781 **/
1782 UINT16
1783 EFIAPI
1784 NetPseudoHeadChecksum (
1785 IN IP4_ADDR Src,
1786 IN IP4_ADDR Dst,
1787 IN UINT8 Proto,
1788 IN UINT16 Len
1789 )
1790 {
1791 NET_PSEUDO_HDR Hdr;
1792
1793 //
1794 // Zero the memory to relieve align problems
1795 //
1796 ZeroMem (&Hdr, sizeof (Hdr));
1797
1798 Hdr.SrcIp = Src;
1799 Hdr.DstIp = Dst;
1800 Hdr.Protocol = Proto;
1801 Hdr.Len = HTONS (Len);
1802
1803 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1804 }
1805
1806 /**
1807 Compute the checksum for TCP6/UDP6 pseudo header.
1808
1809 Src and Dst are in network byte order, and Len is in host byte order.
1810
1811 @param[in] Src The source address of the packet.
1812 @param[in] Dst The destination address of the packet.
1813 @param[in] NextHeader The protocol type of the packet.
1814 @param[in] Len The length of the packet.
1815
1816 @return The computed checksum.
1817
1818 **/
1819 UINT16
1820 NetIp6PseudoHeadChecksum (
1821 IN EFI_IPv6_ADDRESS *Src,
1822 IN EFI_IPv6_ADDRESS *Dst,
1823 IN UINT8 NextHeader,
1824 IN UINT32 Len
1825 )
1826 {
1827 NET_IP6_PSEUDO_HDR Hdr;
1828
1829 //
1830 // Zero the memory to relieve align problems
1831 //
1832 ZeroMem (&Hdr, sizeof (Hdr));
1833
1834 IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);
1835 IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);
1836
1837 Hdr.NextHeader = NextHeader;
1838 Hdr.Len = HTONL (Len);
1839
1840 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1841 }
1842