]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
[Change summary]:
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / NetBuffer.c
1 /** @file
2 Network library functions providing net buffer operation support.
3
4 Copyright (c) 2005 - 2009, 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 /**
513 Create a NET_BUF structure which contains Len byte data of Nbuf starting from
514 Offset.
515
516 A new NET_BUF structure will be created but the associated data in NET_VECTOR
517 is shared. This function exists to do IP packet fragmentation.
518
519 @param[in] Nbuf Pointer to the net buffer to be extracted.
520 @param[in] Offset Starting point of the data to be included in the new
521 net buffer.
522 @param[in] Len Bytes of data to be included in the new net buffer.
523 @param[in] HeadSpace Bytes of head space to reserve for protocol header.
524
525 @return Pointer to the cloned net buffer, or NULL if the
526 allocation failed due to resource limit.
527
528 **/
529 NET_BUF *
530 EFIAPI
531 NetbufGetFragment (
532 IN NET_BUF *Nbuf,
533 IN UINT32 Offset,
534 IN UINT32 Len,
535 IN UINT32 HeadSpace
536 )
537 {
538 NET_BUF *Child;
539 NET_VECTOR *Vector;
540 NET_BLOCK_OP *BlockOp;
541 UINT32 CurBlockOp;
542 UINT32 BlockOpNum;
543 UINT8 *FirstBulk;
544 UINT32 Index;
545 UINT32 First;
546 UINT32 Last;
547 UINT32 FirstSkip;
548 UINT32 FirstLen;
549 UINT32 LastLen;
550 UINT32 Cur;
551
552 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
553
554 if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {
555 return NULL;
556 }
557
558 //
559 // First find the first and last BlockOp that contains
560 // the valid data, and compute the offset of the first
561 // BlockOp and length of the last BlockOp
562 //
563 BlockOp = Nbuf->BlockOp;
564 Cur = 0;
565
566 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
567 if (Offset < Cur + BlockOp[Index].Size) {
568 break;
569 }
570
571 Cur += BlockOp[Index].Size;
572 }
573
574 //
575 // First is the index of the first BlockOp, FirstSkip is
576 // the offset of the first byte in the first BlockOp.
577 //
578 First = Index;
579 FirstSkip = Offset - Cur;
580 FirstLen = BlockOp[Index].Size - FirstSkip;
581
582 //
583 //redundant assignment to make compiler happy.
584 //
585 Last = 0;
586 LastLen = 0;
587
588 if (Len > FirstLen) {
589 Cur += BlockOp[Index].Size;
590 Index++;
591
592 for (; Index < Nbuf->BlockOpNum; Index++) {
593 if (Offset + Len <= Cur + BlockOp[Index].Size) {
594 Last = Index;
595 LastLen = Offset + Len - Cur;
596 break;
597 }
598
599 Cur += BlockOp[Index].Size;
600 }
601
602 } else {
603 Last = First;
604 LastLen = Len;
605 FirstLen = Len;
606 }
607
608 BlockOpNum = Last - First + 1;
609 CurBlockOp = 0;
610
611 if (HeadSpace != 0) {
612 //
613 // Allocate an extra block to accomdate the head space.
614 //
615 BlockOpNum++;
616
617 Child = NetbufAllocStruct (1, BlockOpNum);
618
619 if (Child == NULL) {
620 return NULL;
621 }
622
623 FirstBulk = AllocatePool (HeadSpace);
624
625 if (FirstBulk == NULL) {
626 goto FreeChild;
627 }
628
629 Vector = Child->Vector;
630 Vector->Free = NetbufGetFragmentFree;
631 Vector->Arg = Nbuf->Vector;
632 Vector->Flag = NET_VECTOR_OWN_FIRST;
633 Vector->Len = HeadSpace;
634
635 //
636 // Reserve the head space in the first block
637 //
638 NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);
639 Child->BlockOp[0].Head += HeadSpace;
640 Child->BlockOp[0].Size = 0;
641 CurBlockOp++;
642
643 }else {
644 Child = NetbufAllocStruct (0, BlockOpNum);
645
646 if (Child == NULL) {
647 return NULL;
648 }
649
650 Child->Vector = Nbuf->Vector;
651 }
652
653 NET_GET_REF (Nbuf->Vector);
654 Child->TotalSize = Len;
655
656 //
657 // Set all the BlockOp up, the first and last one are special
658 // and need special process.
659 //
660 NetbufSetBlockOp (
661 Child,
662 Nbuf->BlockOp[First].Head + FirstSkip,
663 FirstLen,
664 CurBlockOp++
665 );
666
667 for (Index = First + 1; Index <= Last - 1 ; Index++) {
668 NetbufSetBlockOp (
669 Child,
670 BlockOp[Index].Head,
671 BlockOp[Index].Size,
672 CurBlockOp++
673 );
674 }
675
676 if (First != Last) {
677 NetbufSetBlockOp (
678 Child,
679 BlockOp[Last].Head,
680 LastLen,
681 CurBlockOp
682 );
683 }
684
685 CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
686 return Child;
687
688 FreeChild:
689
690 FreePool (Child);
691 return NULL;
692 }
693
694
695
696 /**
697 Build a NET_BUF from external blocks.
698
699 A new NET_BUF structure will be created from external blocks. Additional block
700 of memory will be allocated to hold reserved HeadSpace bytes of header room
701 and existing HeadLen bytes of header but the external blocks are shared by the
702 net buffer to avoid data copying.
703
704 @param[in] ExtFragment Pointer to the data block.
705 @param[in] ExtNum The number of the data blocks.
706 @param[in] HeadSpace The head space to be reserved.
707 @param[in] HeadLen The length of the protocol header, This function
708 will pull that number of data into a linear block.
709 @param[in] ExtFree Pointer to the caller provided free function.
710 @param[in] Arg The argument passed to ExtFree when ExtFree is
711 called.
712
713 @return Pointer to the net buffer built from the data blocks,
714 or NULL if the allocation failed due to resource
715 limit.
716
717 **/
718 NET_BUF *
719 EFIAPI
720 NetbufFromExt (
721 IN NET_FRAGMENT *ExtFragment,
722 IN UINT32 ExtNum,
723 IN UINT32 HeadSpace,
724 IN UINT32 HeadLen,
725 IN NET_VECTOR_EXT_FREE ExtFree,
726 IN VOID *Arg OPTIONAL
727 )
728 {
729 NET_BUF *Nbuf;
730 NET_VECTOR *Vector;
731 NET_FRAGMENT SavedFragment;
732 UINT32 SavedIndex;
733 UINT32 TotalLen;
734 UINT32 BlockNum;
735 UINT8 *FirstBlock;
736 UINT32 FirstBlockLen;
737 UINT8 *Header;
738 UINT32 CurBlock;
739 UINT32 Index;
740 UINT32 Len;
741 UINT32 Copied;
742
743 ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));
744
745 SavedFragment.Bulk = NULL;
746 SavedFragment.Len = 0;
747
748 FirstBlockLen = 0;
749 FirstBlock = NULL;
750 BlockNum = ExtNum;
751 Index = 0;
752 TotalLen = 0;
753 SavedIndex = 0;
754 Len = 0;
755 Copied = 0;
756
757 //
758 // No need to consolidate the header if the first block is
759 // longer than the header length or there is only one block.
760 //
761 if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {
762 HeadLen = 0;
763 }
764
765 //
766 // Allocate an extra block if we need to:
767 // 1. Allocate some header space
768 // 2. aggreate the packet header
769 //
770 if ((HeadSpace != 0) || (HeadLen != 0)) {
771 FirstBlockLen = HeadLen + HeadSpace;
772 FirstBlock = AllocatePool (FirstBlockLen);
773
774 if (FirstBlock == NULL) {
775 return NULL;
776 }
777
778 BlockNum++;
779 }
780
781 //
782 // Copy the header to the first block, reduce the NET_BLOCK
783 // to allocate by one for each block that is completely covered
784 // by the first bulk.
785 //
786 if (HeadLen != 0) {
787 Len = HeadLen;
788 Header = FirstBlock + HeadSpace;
789
790 for (Index = 0; Index < ExtNum; Index++) {
791 if (Len >= ExtFragment[Index].Len) {
792 CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);
793
794 Copied += ExtFragment[Index].Len;
795 Len -= ExtFragment[Index].Len;
796 Header += ExtFragment[Index].Len;
797 TotalLen += ExtFragment[Index].Len;
798 BlockNum--;
799
800 if (Len == 0) {
801 //
802 // Increament the index number to point to the next
803 // non-empty fragment.
804 //
805 Index++;
806 break;
807 }
808
809 } else {
810 CopyMem (Header, ExtFragment[Index].Bulk, Len);
811
812 Copied += Len;
813 TotalLen += Len;
814
815 //
816 // Adjust the block structure to exclude the data copied,
817 // So, the left-over block can be processed as other blocks.
818 // But it must be recovered later. (SavedIndex > 0) always
819 // holds since we don't aggreate the header if the first block
820 // is bigger enough that the header is continuous
821 //
822 SavedIndex = Index;
823 SavedFragment = ExtFragment[Index];
824 ExtFragment[Index].Bulk += Len;
825 ExtFragment[Index].Len -= Len;
826 break;
827 }
828 }
829 }
830
831 Nbuf = NetbufAllocStruct (BlockNum, BlockNum);
832
833 if (Nbuf == NULL) {
834 goto FreeFirstBlock;
835 }
836
837 Vector = Nbuf->Vector;
838 Vector->Free = ExtFree;
839 Vector->Arg = Arg;
840 Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);
841
842 //
843 // Set the first block up which may contain
844 // some head space and aggregated header
845 //
846 CurBlock = 0;
847
848 if (FirstBlockLen != 0) {
849 NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);
850 Nbuf->BlockOp[0].Head += HeadSpace;
851 Nbuf->BlockOp[0].Size = Copied;
852
853 CurBlock++;
854 }
855
856 for (; Index < ExtNum; Index++) {
857 NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);
858 TotalLen += ExtFragment[Index].Len;
859 CurBlock++;
860 }
861
862 Vector->Len = TotalLen + HeadSpace;
863 Nbuf->TotalSize = TotalLen;
864
865 if (SavedIndex != 0) {
866 ExtFragment[SavedIndex] = SavedFragment;
867 }
868
869 return Nbuf;
870
871 FreeFirstBlock:
872 if (FirstBlock != NULL) {
873 FreePool (FirstBlock);
874 }
875 return NULL;
876 }
877
878
879 /**
880 Build a fragment table to contain the fragments in the net buffer. This is the
881 opposite operation of the NetbufFromExt.
882
883 @param[in] Nbuf Point to the net buffer.
884 @param[in, out] ExtFragment Pointer to the data block.
885 @param[in, out] ExtNum The number of the data blocks.
886
887 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than
888 ExtNum.
889 @retval EFI_SUCCESS Fragment table is built successfully.
890
891 **/
892 EFI_STATUS
893 EFIAPI
894 NetbufBuildExt (
895 IN NET_BUF *Nbuf,
896 IN OUT NET_FRAGMENT *ExtFragment,
897 IN OUT UINT32 *ExtNum
898 )
899 {
900 UINT32 Index;
901 UINT32 Current;
902
903 Current = 0;
904
905 for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {
906 if (Nbuf->BlockOp[Index].Size == 0) {
907 continue;
908 }
909
910 if (Current < *ExtNum) {
911 ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
912 ExtFragment[Current].Len = Nbuf->BlockOp[Index].Size;
913 Current++;
914 } else {
915 return EFI_BUFFER_TOO_SMALL;
916 }
917 }
918
919 *ExtNum = Current;
920 return EFI_SUCCESS;
921 }
922
923
924 /**
925 Build a net buffer from a list of net buffers.
926
927 All the fragments will be collected from the list of NEW_BUF and then a new
928 net buffer will be created through NetbufFromExt.
929
930 @param[in] BufList A List of the net buffer.
931 @param[in] HeadSpace The head space to be reserved.
932 @param[in] HeaderLen The length of the protocol header, This function
933 will pull that number of data into a linear block.
934 @param[in] ExtFree Pointer to the caller provided free function.
935 @param[in] Arg The argument passed to ExtFree when ExtFree is called.
936
937 @return Pointer to the net buffer built from the list of net
938 buffers.
939
940 **/
941 NET_BUF *
942 EFIAPI
943 NetbufFromBufList (
944 IN LIST_ENTRY *BufList,
945 IN UINT32 HeadSpace,
946 IN UINT32 HeaderLen,
947 IN NET_VECTOR_EXT_FREE ExtFree,
948 IN VOID *Arg OPTIONAL
949 )
950 {
951 NET_FRAGMENT *Fragment;
952 UINT32 FragmentNum;
953 LIST_ENTRY *Entry;
954 NET_BUF *Nbuf;
955 UINT32 Index;
956 UINT32 Current;
957
958 //
959 //Compute how many blocks are there
960 //
961 FragmentNum = 0;
962
963 NET_LIST_FOR_EACH (Entry, BufList) {
964 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
965 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
966 FragmentNum += Nbuf->BlockOpNum;
967 }
968
969 //
970 //Allocate and copy block points
971 //
972 Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);
973
974 if (Fragment == NULL) {
975 return NULL;
976 }
977
978 Current = 0;
979
980 NET_LIST_FOR_EACH (Entry, BufList) {
981 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
982 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
983
984 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
985 if (Nbuf->BlockOp[Index].Size != 0) {
986 Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
987 Fragment[Current].Len = Nbuf->BlockOp[Index].Size;
988 Current++;
989 }
990 }
991 }
992
993 Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);
994 FreePool (Fragment);
995
996 return Nbuf;
997 }
998
999
1000 /**
1001 Reserve some space in the header room of the net buffer.
1002
1003 Upon allocation, all the space are in the tail room of the buffer. Call this
1004 function to move some space to the header room. This function is quite limited
1005 in that it can only reserve space from the first block of an empty NET_BUF not
1006 built from the external. But it should be enough for the network stack.
1007
1008 @param[in, out] Nbuf Pointer to the net buffer.
1009 @param[in] Len The length of buffer to be reserved from the header.
1010
1011 **/
1012 VOID
1013 EFIAPI
1014 NetbufReserve (
1015 IN OUT NET_BUF *Nbuf,
1016 IN UINT32 Len
1017 )
1018 {
1019 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1020 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
1021
1022 ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));
1023 ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));
1024
1025 Nbuf->BlockOp[0].Head += Len;
1026 Nbuf->BlockOp[0].Tail += Len;
1027
1028 ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);
1029 }
1030
1031
1032 /**
1033 Allocate Len bytes of space from the header or tail of the buffer.
1034
1035 @param[in, out] Nbuf Pointer to the net buffer.
1036 @param[in] Len The length of the buffer to be allocated.
1037 @param[in] FromHead The flag to indicate whether reserve the data
1038 from head (TRUE) or tail (FALSE).
1039
1040 @return Pointer to the first byte of the allocated buffer,
1041 or NULL if there is no sufficient space.
1042
1043 **/
1044 UINT8*
1045 EFIAPI
1046 NetbufAllocSpace (
1047 IN OUT NET_BUF *Nbuf,
1048 IN UINT32 Len,
1049 IN BOOLEAN FromHead
1050 )
1051 {
1052 NET_BLOCK_OP *BlockOp;
1053 UINT32 Index;
1054 UINT8 *SavedTail;
1055
1056 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1057 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
1058
1059 ASSERT (Len > 0);
1060
1061 if (FromHead) {
1062 //
1063 // Allocate some space from head. If the buffer is empty,
1064 // allocate from the first block. If it isn't, allocate
1065 // from the first non-empty block, or the block before that.
1066 //
1067 if (Nbuf->TotalSize == 0) {
1068 Index = 0;
1069 } else {
1070 NetbufGetByte (Nbuf, 0, &Index);
1071
1072 if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
1073 Index--;
1074 }
1075 }
1076
1077 BlockOp = &(Nbuf->BlockOp[Index]);
1078
1079 if (NET_HEADSPACE (BlockOp) < Len) {
1080 return NULL;
1081 }
1082
1083 BlockOp->Head -= Len;
1084 BlockOp->Size += Len;
1085 Nbuf->TotalSize += Len;
1086
1087 return BlockOp->Head;
1088
1089 } else {
1090 //
1091 // Allocate some space from the tail. If the buffer is empty,
1092 // allocate from the first block. If it isn't, allocate
1093 // from the last non-empty block, or the block after that.
1094 //
1095 if (Nbuf->TotalSize == 0) {
1096 Index = 0;
1097 } else {
1098 NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
1099
1100 if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
1101 (Index < Nbuf->BlockOpNum - 1)) {
1102
1103 Index++;
1104 }
1105 }
1106
1107 BlockOp = &(Nbuf->BlockOp[Index]);
1108
1109 if (NET_TAILSPACE (BlockOp) < Len) {
1110 return NULL;
1111 }
1112
1113 SavedTail = BlockOp->Tail;
1114
1115 BlockOp->Tail += Len;
1116 BlockOp->Size += Len;
1117 Nbuf->TotalSize += Len;
1118
1119 return SavedTail;
1120 }
1121 }
1122
1123
1124 /**
1125 Trim a single NET_BLOCK by Len bytes from the header or tail.
1126
1127 @param[in, out] BlockOp Pointer to the NET_BLOCK.
1128 @param[in] Len The length of the data to be trimmed.
1129 @param[in] FromHead The flag to indicate whether trim data from head
1130 (TRUE) or tail (FALSE).
1131
1132 **/
1133 VOID
1134 NetblockTrim (
1135 IN OUT NET_BLOCK_OP *BlockOp,
1136 IN UINT32 Len,
1137 IN BOOLEAN FromHead
1138 )
1139 {
1140 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));
1141
1142 BlockOp->Size -= Len;
1143
1144 if (FromHead) {
1145 BlockOp->Head += Len;
1146 } else {
1147 BlockOp->Tail -= Len;
1148 }
1149 }
1150
1151
1152 /**
1153 Trim Len bytes from the header or tail of the net buffer.
1154
1155 @param[in, out] Nbuf Pointer to the net buffer.
1156 @param[in] Len The length of the data to be trimmed.
1157 @param[in] FromHead The flag to indicate whether trim data from head
1158 (TRUE) or tail (FALSE).
1159
1160 @return Length of the actually trimmed data, which is possible to be less
1161 than Len because the TotalSize of Nbuf is less than Len.
1162
1163 **/
1164 UINT32
1165 EFIAPI
1166 NetbufTrim (
1167 IN OUT NET_BUF *Nbuf,
1168 IN UINT32 Len,
1169 IN BOOLEAN FromHead
1170 )
1171 {
1172 NET_BLOCK_OP *BlockOp;
1173 UINT32 Index;
1174 UINT32 Trimmed;
1175
1176 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1177
1178 if (Len > Nbuf->TotalSize) {
1179 Len = Nbuf->TotalSize;
1180 }
1181
1182 //
1183 // If FromTail is true, iterate backward. That
1184 // is, init Index to NBuf->BlockNum - 1, and
1185 // decrease it by 1 during each loop. Otherwise,
1186 // iterate forward. That is, init Index to 0, and
1187 // increase it by 1 during each loop.
1188 //
1189 Trimmed = 0;
1190 Nbuf->TotalSize -= Len;
1191
1192 Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
1193 BlockOp = Nbuf->BlockOp;
1194
1195 for (;;) {
1196 if (BlockOp[Index].Size == 0) {
1197 Index += (FromHead ? 1 : -1);
1198 continue;
1199 }
1200
1201 if (Len > BlockOp[Index].Size) {
1202 Len -= BlockOp[Index].Size;
1203 Trimmed += BlockOp[Index].Size;
1204 NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
1205 } else {
1206 Trimmed += Len;
1207 NetblockTrim (&BlockOp[Index], Len, FromHead);
1208 break;
1209 }
1210
1211 Index += (FromHead ? 1 : -1);
1212 }
1213
1214 return Trimmed;
1215 }
1216
1217
1218 /**
1219 Copy Len bytes of data from the specific offset of the net buffer to the
1220 destination memory.
1221
1222 The Len bytes of data may cross the several fragments of the net buffer.
1223
1224 @param[in] Nbuf Pointer to the net buffer.
1225 @param[in] Offset The sequence number of the first byte to copy.
1226 @param[in] Len Length of the data to copy.
1227 @param[in] Dest The destination of the data to copy to.
1228
1229 @return The length of the actual copied data, or 0 if the offset
1230 specified exceeds the total size of net buffer.
1231
1232 **/
1233 UINT32
1234 EFIAPI
1235 NetbufCopy (
1236 IN NET_BUF *Nbuf,
1237 IN UINT32 Offset,
1238 IN UINT32 Len,
1239 IN UINT8 *Dest
1240 )
1241 {
1242 NET_BLOCK_OP *BlockOp;
1243 UINT32 Skip;
1244 UINT32 Left;
1245 UINT32 Copied;
1246 UINT32 Index;
1247 UINT32 Cur;
1248
1249 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1250 ASSERT (Dest);
1251
1252 if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
1253 return 0;
1254 }
1255
1256 if (Nbuf->TotalSize - Offset < Len) {
1257 Len = Nbuf->TotalSize - Offset;
1258 }
1259
1260 BlockOp = Nbuf->BlockOp;
1261
1262 //
1263 // Skip to the offset. Don't make "Offset-By-One" error here.
1264 // Cur + BLOCK.SIZE is the first sequence number of next block.
1265 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
1266 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
1267 // first byte is the next block's first byte.
1268 //
1269 Cur = 0;
1270
1271 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1272 if (BlockOp[Index].Size == 0) {
1273 continue;
1274 }
1275
1276 if (Offset < Cur + BlockOp[Index].Size) {
1277 break;
1278 }
1279
1280 Cur += BlockOp[Index].Size;
1281 }
1282
1283 //
1284 // Cur is the sequence number of the first byte in the block
1285 // Offset - Cur is the number of bytes before first byte to
1286 // to copy in the current block.
1287 //
1288 Skip = Offset - Cur;
1289 Left = BlockOp[Index].Size - Skip;
1290
1291 if (Len <= Left) {
1292 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);
1293 return Len;
1294 }
1295
1296 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);
1297
1298 Dest += Left;
1299 Len -= Left;
1300 Copied = Left;
1301
1302 Index++;
1303
1304 for (; Index < Nbuf->BlockOpNum; Index++) {
1305 if (Len > BlockOp[Index].Size) {
1306 Len -= BlockOp[Index].Size;
1307 Copied += BlockOp[Index].Size;
1308
1309 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
1310 Dest += BlockOp[Index].Size;
1311 } else {
1312 Copied += Len;
1313 CopyMem (Dest, BlockOp[Index].Head, Len);
1314 break;
1315 }
1316 }
1317
1318 return Copied;
1319 }
1320
1321
1322 /**
1323 Initiate the net buffer queue.
1324
1325 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.
1326
1327 **/
1328 VOID
1329 EFIAPI
1330 NetbufQueInit (
1331 IN OUT NET_BUF_QUEUE *NbufQue
1332 )
1333 {
1334 NbufQue->Signature = NET_QUE_SIGNATURE;
1335 NbufQue->RefCnt = 1;
1336 InitializeListHead (&NbufQue->List);
1337
1338 InitializeListHead (&NbufQue->BufList);
1339 NbufQue->BufSize = 0;
1340 NbufQue->BufNum = 0;
1341 }
1342
1343
1344 /**
1345 Allocate and initialize a net buffer queue.
1346
1347 @return Pointer to the allocated net buffer queue, or NULL if the
1348 allocation failed due to resource limit.
1349
1350 **/
1351 NET_BUF_QUEUE *
1352 EFIAPI
1353 NetbufQueAlloc (
1354 VOID
1355 )
1356 {
1357 NET_BUF_QUEUE *NbufQue;
1358
1359 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));
1360 if (NbufQue == NULL) {
1361 return NULL;
1362 }
1363
1364 NetbufQueInit (NbufQue);
1365
1366 return NbufQue;
1367 }
1368
1369
1370 /**
1371 Free a net buffer queue.
1372
1373 Decrease the reference count of the net buffer queue by one. The real resource
1374 free operation isn't performed until the reference count of the net buffer
1375 queue is decreased to 0.
1376
1377 @param[in] NbufQue Pointer to the net buffer queue to be freed.
1378
1379 **/
1380 VOID
1381 EFIAPI
1382 NetbufQueFree (
1383 IN NET_BUF_QUEUE *NbufQue
1384 )
1385 {
1386 ASSERT (NbufQue != NULL);
1387 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1388
1389 NbufQue->RefCnt--;
1390
1391 if (NbufQue->RefCnt == 0) {
1392 NetbufQueFlush (NbufQue);
1393 FreePool (NbufQue);
1394 }
1395 }
1396
1397
1398 /**
1399 Append a net buffer to the net buffer queue.
1400
1401 @param[in, out] NbufQue Pointer to the net buffer queue.
1402 @param[in, out] Nbuf Pointer to the net buffer to be appended.
1403
1404 **/
1405 VOID
1406 EFIAPI
1407 NetbufQueAppend (
1408 IN OUT NET_BUF_QUEUE *NbufQue,
1409 IN OUT NET_BUF *Nbuf
1410 )
1411 {
1412 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1413 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1414
1415 InsertTailList (&NbufQue->BufList, &Nbuf->List);
1416
1417 NbufQue->BufSize += Nbuf->TotalSize;
1418 NbufQue->BufNum++;
1419 }
1420
1421
1422 /**
1423 Remove a net buffer from the head in the specific queue and return it.
1424
1425 @param[in, out] NbufQue Pointer to the net buffer queue.
1426
1427 @return Pointer to the net buffer removed from the specific queue,
1428 or NULL if there is no net buffer in the specific queue.
1429
1430 **/
1431 NET_BUF *
1432 EFIAPI
1433 NetbufQueRemove (
1434 IN OUT NET_BUF_QUEUE *NbufQue
1435 )
1436 {
1437 NET_BUF *First;
1438
1439 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1440
1441 if (NbufQue->BufNum == 0) {
1442 return NULL;
1443 }
1444
1445 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
1446
1447 NetListRemoveHead (&NbufQue->BufList);
1448
1449 NbufQue->BufSize -= First->TotalSize;
1450 NbufQue->BufNum--;
1451 return First;
1452 }
1453
1454
1455 /**
1456 Copy Len bytes of data from the net buffer queue at the specific offset to the
1457 destination memory.
1458
1459 The copying operation is the same as NetbufCopy but applies to the net buffer
1460 queue instead of the net buffer.
1461
1462 @param[in] NbufQue Pointer to the net buffer queue.
1463 @param[in] Offset The sequence number of the first byte to copy.
1464 @param[in] Len Length of the data to copy.
1465 @param[out] Dest The destination of the data to copy to.
1466
1467 @return The length of the actual copied data, or 0 if the offset
1468 specified exceeds the total size of net buffer queue.
1469
1470 **/
1471 UINT32
1472 EFIAPI
1473 NetbufQueCopy (
1474 IN NET_BUF_QUEUE *NbufQue,
1475 IN UINT32 Offset,
1476 IN UINT32 Len,
1477 OUT UINT8 *Dest
1478 )
1479 {
1480 LIST_ENTRY *Entry;
1481 NET_BUF *Nbuf;
1482 UINT32 Skip;
1483 UINT32 Left;
1484 UINT32 Cur;
1485 UINT32 Copied;
1486
1487 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1488 ASSERT (Dest != NULL);
1489
1490 if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
1491 return 0;
1492 }
1493
1494 if (NbufQue->BufSize - Offset < Len) {
1495 Len = NbufQue->BufSize - Offset;
1496 }
1497
1498 //
1499 // skip to the Offset
1500 //
1501 Cur = 0;
1502 Nbuf = NULL;
1503
1504 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
1505 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1506
1507 if (Offset < Cur + Nbuf->TotalSize) {
1508 break;
1509 }
1510
1511 Cur += Nbuf->TotalSize;
1512 }
1513
1514 ASSERT (Nbuf != NULL);
1515
1516 //
1517 // Copy the data in the first buffer.
1518 //
1519 Skip = Offset - Cur;
1520 Left = Nbuf->TotalSize - Skip;
1521
1522 if (Len < Left) {
1523 return NetbufCopy (Nbuf, Skip, Len, Dest);
1524 }
1525
1526 NetbufCopy (Nbuf, Skip, Left, Dest);
1527 Dest += Left;
1528 Len -= Left;
1529 Copied = Left;
1530
1531 //
1532 // Iterate over the others
1533 //
1534 Entry = Entry->ForwardLink;
1535
1536 while ((Len > 0) && (Entry != &NbufQue->BufList)) {
1537 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1538
1539 if (Len > Nbuf->TotalSize) {
1540 Len -= Nbuf->TotalSize;
1541 Copied += Nbuf->TotalSize;
1542
1543 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
1544 Dest += Nbuf->TotalSize;
1545
1546 } else {
1547 NetbufCopy (Nbuf, 0, Len, Dest);
1548 Copied += Len;
1549 break;
1550 }
1551
1552 Entry = Entry->ForwardLink;
1553 }
1554
1555 return Copied;
1556 }
1557
1558
1559 /**
1560 Trim Len bytes of data from the queue header, release any of the net buffer
1561 whom is trimmed wholely.
1562
1563 The trimming operation is the same as NetbufTrim but applies to the net buffer
1564 queue instead of the net buffer.
1565
1566 @param[in, out] NbufQue Pointer to the net buffer queue.
1567 @param[in] Len Length of the data to trim.
1568
1569 @return The actual length of the data trimmed.
1570
1571 **/
1572 UINT32
1573 EFIAPI
1574 NetbufQueTrim (
1575 IN OUT NET_BUF_QUEUE *NbufQue,
1576 IN UINT32 Len
1577 )
1578 {
1579 LIST_ENTRY *Entry;
1580 LIST_ENTRY *Next;
1581 NET_BUF *Nbuf;
1582 UINT32 Trimmed;
1583
1584 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1585
1586 if (Len == 0) {
1587 return 0;
1588 }
1589
1590 if (Len > NbufQue->BufSize) {
1591 Len = NbufQue->BufSize;
1592 }
1593
1594 NbufQue->BufSize -= Len;
1595 Trimmed = 0;
1596
1597 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
1598 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1599
1600 if (Len >= Nbuf->TotalSize) {
1601 Trimmed += Nbuf->TotalSize;
1602 Len -= Nbuf->TotalSize;
1603
1604 RemoveEntryList (Entry);
1605 NetbufFree (Nbuf);
1606
1607 NbufQue->BufNum--;
1608
1609 if (Len == 0) {
1610 break;
1611 }
1612
1613 } else {
1614 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
1615 break;
1616 }
1617 }
1618
1619 return Trimmed;
1620 }
1621
1622
1623 /**
1624 Flush the net buffer queue.
1625
1626 @param[in, out] NbufQue Pointer to the queue to be flushed.
1627
1628 **/
1629 VOID
1630 EFIAPI
1631 NetbufQueFlush (
1632 IN OUT NET_BUF_QUEUE *NbufQue
1633 )
1634 {
1635 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1636
1637 NetbufFreeList (&NbufQue->BufList);
1638
1639 NbufQue->BufNum = 0;
1640 NbufQue->BufSize = 0;
1641 }
1642
1643
1644 /**
1645 Compute the checksum for a bulk of data.
1646
1647 @param[in] Bulk Pointer to the data.
1648 @param[in] Len Length of the data, in bytes.
1649
1650 @return The computed checksum.
1651
1652 **/
1653 UINT16
1654 EFIAPI
1655 NetblockChecksum (
1656 IN UINT8 *Bulk,
1657 IN UINT32 Len
1658 )
1659 {
1660 register UINT32 Sum;
1661
1662 Sum = 0;
1663
1664 while (Len > 1) {
1665 Sum += *(UINT16 *) Bulk;
1666 Bulk += 2;
1667 Len -= 2;
1668 }
1669
1670 //
1671 // Add left-over byte, if any
1672 //
1673 if (Len > 0) {
1674 Sum += *(UINT8 *) Bulk;
1675 }
1676
1677 //
1678 // Fold 32-bit sum to 16 bits
1679 //
1680 while ((Sum >> 16) != 0) {
1681 Sum = (Sum & 0xffff) + (Sum >> 16);
1682
1683 }
1684
1685 return (UINT16) Sum;
1686 }
1687
1688
1689 /**
1690 Add two checksums.
1691
1692 @param[in] Checksum1 The first checksum to be added.
1693 @param[in] Checksum2 The second checksum to be added.
1694
1695 @return The new checksum.
1696
1697 **/
1698 UINT16
1699 EFIAPI
1700 NetAddChecksum (
1701 IN UINT16 Checksum1,
1702 IN UINT16 Checksum2
1703 )
1704 {
1705 UINT32 Sum;
1706
1707 Sum = Checksum1 + Checksum2;
1708
1709 //
1710 // two UINT16 can only add up to a carry of 1.
1711 //
1712 if ((Sum >> 16) != 0) {
1713 Sum = (Sum & 0xffff) + 1;
1714
1715 }
1716
1717 return (UINT16) Sum;
1718 }
1719
1720
1721 /**
1722 Compute the checksum for a NET_BUF.
1723
1724 @param[in] Nbuf Pointer to the net buffer.
1725
1726 @return The computed checksum.
1727
1728 **/
1729 UINT16
1730 EFIAPI
1731 NetbufChecksum (
1732 IN NET_BUF *Nbuf
1733 )
1734 {
1735 NET_BLOCK_OP *BlockOp;
1736 UINT32 Offset;
1737 UINT16 TotalSum;
1738 UINT16 BlockSum;
1739 UINT32 Index;
1740
1741 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1742
1743 TotalSum = 0;
1744 Offset = 0;
1745 BlockOp = Nbuf->BlockOp;
1746
1747 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1748 if (BlockOp[Index].Size == 0) {
1749 continue;
1750 }
1751
1752 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
1753
1754 if ((Offset & 0x01) != 0) {
1755 //
1756 // The checksum starts with an odd byte, swap
1757 // the checksum before added to total checksum
1758 //
1759 BlockSum = (UINT16) NET_SWAP_SHORT (BlockSum);
1760 }
1761
1762 TotalSum = NetAddChecksum (BlockSum, TotalSum);
1763 Offset += BlockOp[Index].Size;
1764 }
1765
1766 return TotalSum;
1767 }
1768
1769
1770 /**
1771 Compute the checksum for TCP/UDP pseudo header.
1772
1773 Src and Dst are in network byte order, and Len is in host byte order.
1774
1775 @param[in] Src The source address of the packet.
1776 @param[in] Dst The destination address of the packet.
1777 @param[in] Proto The protocol type of the packet.
1778 @param[in] Len The length of the packet.
1779
1780 @return The computed checksum.
1781
1782 **/
1783 UINT16
1784 EFIAPI
1785 NetPseudoHeadChecksum (
1786 IN IP4_ADDR Src,
1787 IN IP4_ADDR Dst,
1788 IN UINT8 Proto,
1789 IN UINT16 Len
1790 )
1791 {
1792 NET_PSEUDO_HDR Hdr;
1793
1794 //
1795 // Zero the memory to relieve align problems
1796 //
1797 ZeroMem (&Hdr, sizeof (Hdr));
1798
1799 Hdr.SrcIp = Src;
1800 Hdr.DstIp = Dst;
1801 Hdr.Protocol = Proto;
1802 Hdr.Len = HTONS (Len);
1803
1804 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1805 }
1806
1807 /**
1808 Compute the checksum for TCP6/UDP6 pseudo header.
1809
1810 Src and Dst are in network byte order, and Len is in host byte order.
1811
1812 @param[in] Src The source address of the packet.
1813 @param[in] Dst The destination address of the packet.
1814 @param[in] NextHeader The protocol type of the packet.
1815 @param[in] Len The length of the packet.
1816
1817 @return The computed checksum.
1818
1819 **/
1820 UINT16
1821 NetIp6PseudoHeadChecksum (
1822 IN EFI_IPv6_ADDRESS *Src,
1823 IN EFI_IPv6_ADDRESS *Dst,
1824 IN UINT8 NextHeader,
1825 IN UINT32 Len
1826 )
1827 {
1828 NET_IP6_PSEUDO_HDR Hdr;
1829
1830 //
1831 // Zero the memory to relieve align problems
1832 //
1833 ZeroMem (&Hdr, sizeof (Hdr));
1834
1835 IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);
1836 IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);
1837
1838 Hdr.NextHeader = NextHeader;
1839 Hdr.Len = HTONL (Len);
1840
1841 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1842 }
1843