]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
1. Fix the potential issue in NetbufGetFragment() when Last is zero in Line 53.
[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 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1054 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
1055
1056 ASSERT (Len > 0);
1057
1058 if (FromHead) {
1059 //
1060 // Allocate some space from head. If the buffer is empty,
1061 // allocate from the first block. If it isn't, allocate
1062 // from the first non-empty block, or the block before that.
1063 //
1064 if (Nbuf->TotalSize == 0) {
1065 Index = 0;
1066 } else {
1067 NetbufGetByte (Nbuf, 0, &Index);
1068
1069 if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
1070 Index--;
1071 }
1072 }
1073
1074 BlockOp = &(Nbuf->BlockOp[Index]);
1075
1076 if (NET_HEADSPACE (BlockOp) < Len) {
1077 return NULL;
1078 }
1079
1080 BlockOp->Head -= Len;
1081 BlockOp->Size += Len;
1082 Nbuf->TotalSize += Len;
1083
1084 return BlockOp->Head;
1085
1086 } else {
1087 //
1088 // Allocate some space from the tail. If the buffer is empty,
1089 // allocate from the first block. If it isn't, allocate
1090 // from the last non-empty block, or the block after that.
1091 //
1092 if (Nbuf->TotalSize == 0) {
1093 Index = 0;
1094 } else {
1095 NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
1096
1097 if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
1098 (Index < Nbuf->BlockOpNum - 1)) {
1099
1100 Index++;
1101 }
1102 }
1103
1104 BlockOp = &(Nbuf->BlockOp[Index]);
1105
1106 if (NET_TAILSPACE (BlockOp) < Len) {
1107 return NULL;
1108 }
1109
1110 SavedTail = BlockOp->Tail;
1111
1112 BlockOp->Tail += Len;
1113 BlockOp->Size += Len;
1114 Nbuf->TotalSize += Len;
1115
1116 return SavedTail;
1117 }
1118 }
1119
1120
1121 /**
1122 Trim a single NET_BLOCK by Len bytes from the header or tail.
1123
1124 @param[in, out] BlockOp Pointer to the NET_BLOCK.
1125 @param[in] Len The length of the data to be trimmed.
1126 @param[in] FromHead The flag to indicate whether trim data from head
1127 (TRUE) or tail (FALSE).
1128
1129 **/
1130 VOID
1131 NetblockTrim (
1132 IN OUT NET_BLOCK_OP *BlockOp,
1133 IN UINT32 Len,
1134 IN BOOLEAN FromHead
1135 )
1136 {
1137 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));
1138
1139 BlockOp->Size -= Len;
1140
1141 if (FromHead) {
1142 BlockOp->Head += Len;
1143 } else {
1144 BlockOp->Tail -= Len;
1145 }
1146 }
1147
1148
1149 /**
1150 Trim Len bytes from the header or tail of the net buffer.
1151
1152 @param[in, out] Nbuf Pointer to the net buffer.
1153 @param[in] Len The length of the data to be trimmed.
1154 @param[in] FromHead The flag to indicate whether trim data from head
1155 (TRUE) or tail (FALSE).
1156
1157 @return Length of the actually trimmed data, which is possible to be less
1158 than Len because the TotalSize of Nbuf is less than Len.
1159
1160 **/
1161 UINT32
1162 EFIAPI
1163 NetbufTrim (
1164 IN OUT NET_BUF *Nbuf,
1165 IN UINT32 Len,
1166 IN BOOLEAN FromHead
1167 )
1168 {
1169 NET_BLOCK_OP *BlockOp;
1170 UINT32 Index;
1171 UINT32 Trimmed;
1172
1173 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1174
1175 if (Len > Nbuf->TotalSize) {
1176 Len = Nbuf->TotalSize;
1177 }
1178
1179 //
1180 // If FromTail is true, iterate backward. That
1181 // is, init Index to NBuf->BlockNum - 1, and
1182 // decrease it by 1 during each loop. Otherwise,
1183 // iterate forward. That is, init Index to 0, and
1184 // increase it by 1 during each loop.
1185 //
1186 Trimmed = 0;
1187 Nbuf->TotalSize -= Len;
1188
1189 Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
1190 BlockOp = Nbuf->BlockOp;
1191
1192 for (;;) {
1193 if (BlockOp[Index].Size == 0) {
1194 Index += (FromHead ? 1 : -1);
1195 continue;
1196 }
1197
1198 if (Len > BlockOp[Index].Size) {
1199 Len -= BlockOp[Index].Size;
1200 Trimmed += BlockOp[Index].Size;
1201 NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
1202 } else {
1203 Trimmed += Len;
1204 NetblockTrim (&BlockOp[Index], Len, FromHead);
1205 break;
1206 }
1207
1208 Index += (FromHead ? 1 : -1);
1209 }
1210
1211 return Trimmed;
1212 }
1213
1214
1215 /**
1216 Copy Len bytes of data from the specific offset of the net buffer to the
1217 destination memory.
1218
1219 The Len bytes of data may cross the several fragments of the net buffer.
1220
1221 @param[in] Nbuf Pointer to the net buffer.
1222 @param[in] Offset The sequence number of the first byte to copy.
1223 @param[in] Len Length of the data to copy.
1224 @param[in] Dest The destination of the data to copy to.
1225
1226 @return The length of the actual copied data, or 0 if the offset
1227 specified exceeds the total size of net buffer.
1228
1229 **/
1230 UINT32
1231 EFIAPI
1232 NetbufCopy (
1233 IN NET_BUF *Nbuf,
1234 IN UINT32 Offset,
1235 IN UINT32 Len,
1236 IN UINT8 *Dest
1237 )
1238 {
1239 NET_BLOCK_OP *BlockOp;
1240 UINT32 Skip;
1241 UINT32 Left;
1242 UINT32 Copied;
1243 UINT32 Index;
1244 UINT32 Cur;
1245
1246 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1247 ASSERT (Dest);
1248
1249 if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
1250 return 0;
1251 }
1252
1253 if (Nbuf->TotalSize - Offset < Len) {
1254 Len = Nbuf->TotalSize - Offset;
1255 }
1256
1257 BlockOp = Nbuf->BlockOp;
1258
1259 //
1260 // Skip to the offset. Don't make "Offset-By-One" error here.
1261 // Cur + BLOCK.SIZE is the first sequence number of next block.
1262 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
1263 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
1264 // first byte is the next block's first byte.
1265 //
1266 Cur = 0;
1267
1268 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1269 if (BlockOp[Index].Size == 0) {
1270 continue;
1271 }
1272
1273 if (Offset < Cur + BlockOp[Index].Size) {
1274 break;
1275 }
1276
1277 Cur += BlockOp[Index].Size;
1278 }
1279
1280 //
1281 // Cur is the sequence number of the first byte in the block
1282 // Offset - Cur is the number of bytes before first byte to
1283 // to copy in the current block.
1284 //
1285 Skip = Offset - Cur;
1286 Left = BlockOp[Index].Size - Skip;
1287
1288 if (Len <= Left) {
1289 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);
1290 return Len;
1291 }
1292
1293 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);
1294
1295 Dest += Left;
1296 Len -= Left;
1297 Copied = Left;
1298
1299 Index++;
1300
1301 for (; Index < Nbuf->BlockOpNum; Index++) {
1302 if (Len > BlockOp[Index].Size) {
1303 Len -= BlockOp[Index].Size;
1304 Copied += BlockOp[Index].Size;
1305
1306 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
1307 Dest += BlockOp[Index].Size;
1308 } else {
1309 Copied += Len;
1310 CopyMem (Dest, BlockOp[Index].Head, Len);
1311 break;
1312 }
1313 }
1314
1315 return Copied;
1316 }
1317
1318
1319 /**
1320 Initiate the net buffer queue.
1321
1322 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.
1323
1324 **/
1325 VOID
1326 EFIAPI
1327 NetbufQueInit (
1328 IN OUT NET_BUF_QUEUE *NbufQue
1329 )
1330 {
1331 NbufQue->Signature = NET_QUE_SIGNATURE;
1332 NbufQue->RefCnt = 1;
1333 InitializeListHead (&NbufQue->List);
1334
1335 InitializeListHead (&NbufQue->BufList);
1336 NbufQue->BufSize = 0;
1337 NbufQue->BufNum = 0;
1338 }
1339
1340
1341 /**
1342 Allocate and initialize a net buffer queue.
1343
1344 @return Pointer to the allocated net buffer queue, or NULL if the
1345 allocation failed due to resource limit.
1346
1347 **/
1348 NET_BUF_QUEUE *
1349 EFIAPI
1350 NetbufQueAlloc (
1351 VOID
1352 )
1353 {
1354 NET_BUF_QUEUE *NbufQue;
1355
1356 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));
1357 if (NbufQue == NULL) {
1358 return NULL;
1359 }
1360
1361 NetbufQueInit (NbufQue);
1362
1363 return NbufQue;
1364 }
1365
1366
1367 /**
1368 Free a net buffer queue.
1369
1370 Decrease the reference count of the net buffer queue by one. The real resource
1371 free operation isn't performed until the reference count of the net buffer
1372 queue is decreased to 0.
1373
1374 @param[in] NbufQue Pointer to the net buffer queue to be freed.
1375
1376 **/
1377 VOID
1378 EFIAPI
1379 NetbufQueFree (
1380 IN NET_BUF_QUEUE *NbufQue
1381 )
1382 {
1383 ASSERT (NbufQue != NULL);
1384 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1385
1386 NbufQue->RefCnt--;
1387
1388 if (NbufQue->RefCnt == 0) {
1389 NetbufQueFlush (NbufQue);
1390 FreePool (NbufQue);
1391 }
1392 }
1393
1394
1395 /**
1396 Append a net buffer to the net buffer queue.
1397
1398 @param[in, out] NbufQue Pointer to the net buffer queue.
1399 @param[in, out] Nbuf Pointer to the net buffer to be appended.
1400
1401 **/
1402 VOID
1403 EFIAPI
1404 NetbufQueAppend (
1405 IN OUT NET_BUF_QUEUE *NbufQue,
1406 IN OUT NET_BUF *Nbuf
1407 )
1408 {
1409 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1410 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1411
1412 InsertTailList (&NbufQue->BufList, &Nbuf->List);
1413
1414 NbufQue->BufSize += Nbuf->TotalSize;
1415 NbufQue->BufNum++;
1416 }
1417
1418
1419 /**
1420 Remove a net buffer from the head in the specific queue and return it.
1421
1422 @param[in, out] NbufQue Pointer to the net buffer queue.
1423
1424 @return Pointer to the net buffer removed from the specific queue,
1425 or NULL if there is no net buffer in the specific queue.
1426
1427 **/
1428 NET_BUF *
1429 EFIAPI
1430 NetbufQueRemove (
1431 IN OUT NET_BUF_QUEUE *NbufQue
1432 )
1433 {
1434 NET_BUF *First;
1435
1436 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1437
1438 if (NbufQue->BufNum == 0) {
1439 return NULL;
1440 }
1441
1442 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
1443
1444 NetListRemoveHead (&NbufQue->BufList);
1445
1446 NbufQue->BufSize -= First->TotalSize;
1447 NbufQue->BufNum--;
1448 return First;
1449 }
1450
1451
1452 /**
1453 Copy Len bytes of data from the net buffer queue at the specific offset to the
1454 destination memory.
1455
1456 The copying operation is the same as NetbufCopy but applies to the net buffer
1457 queue instead of the net buffer.
1458
1459 @param[in] NbufQue Pointer to the net buffer queue.
1460 @param[in] Offset The sequence number of the first byte to copy.
1461 @param[in] Len Length of the data to copy.
1462 @param[out] Dest The destination of the data to copy to.
1463
1464 @return The length of the actual copied data, or 0 if the offset
1465 specified exceeds the total size of net buffer queue.
1466
1467 **/
1468 UINT32
1469 EFIAPI
1470 NetbufQueCopy (
1471 IN NET_BUF_QUEUE *NbufQue,
1472 IN UINT32 Offset,
1473 IN UINT32 Len,
1474 OUT UINT8 *Dest
1475 )
1476 {
1477 LIST_ENTRY *Entry;
1478 NET_BUF *Nbuf;
1479 UINT32 Skip;
1480 UINT32 Left;
1481 UINT32 Cur;
1482 UINT32 Copied;
1483
1484 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1485 ASSERT (Dest != NULL);
1486
1487 if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
1488 return 0;
1489 }
1490
1491 if (NbufQue->BufSize - Offset < Len) {
1492 Len = NbufQue->BufSize - Offset;
1493 }
1494
1495 //
1496 // skip to the Offset
1497 //
1498 Cur = 0;
1499 Nbuf = NULL;
1500
1501 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
1502 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1503
1504 if (Offset < Cur + Nbuf->TotalSize) {
1505 break;
1506 }
1507
1508 Cur += Nbuf->TotalSize;
1509 }
1510
1511 ASSERT (Nbuf != NULL);
1512
1513 //
1514 // Copy the data in the first buffer.
1515 //
1516 Skip = Offset - Cur;
1517 Left = Nbuf->TotalSize - Skip;
1518
1519 if (Len < Left) {
1520 return NetbufCopy (Nbuf, Skip, Len, Dest);
1521 }
1522
1523 NetbufCopy (Nbuf, Skip, Left, Dest);
1524 Dest += Left;
1525 Len -= Left;
1526 Copied = Left;
1527
1528 //
1529 // Iterate over the others
1530 //
1531 Entry = Entry->ForwardLink;
1532
1533 while ((Len > 0) && (Entry != &NbufQue->BufList)) {
1534 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1535
1536 if (Len > Nbuf->TotalSize) {
1537 Len -= Nbuf->TotalSize;
1538 Copied += Nbuf->TotalSize;
1539
1540 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
1541 Dest += Nbuf->TotalSize;
1542
1543 } else {
1544 NetbufCopy (Nbuf, 0, Len, Dest);
1545 Copied += Len;
1546 break;
1547 }
1548
1549 Entry = Entry->ForwardLink;
1550 }
1551
1552 return Copied;
1553 }
1554
1555
1556 /**
1557 Trim Len bytes of data from the queue header, release any of the net buffer
1558 whom is trimmed wholely.
1559
1560 The trimming operation is the same as NetbufTrim but applies to the net buffer
1561 queue instead of the net buffer.
1562
1563 @param[in, out] NbufQue Pointer to the net buffer queue.
1564 @param[in] Len Length of the data to trim.
1565
1566 @return The actual length of the data trimmed.
1567
1568 **/
1569 UINT32
1570 EFIAPI
1571 NetbufQueTrim (
1572 IN OUT NET_BUF_QUEUE *NbufQue,
1573 IN UINT32 Len
1574 )
1575 {
1576 LIST_ENTRY *Entry;
1577 LIST_ENTRY *Next;
1578 NET_BUF *Nbuf;
1579 UINT32 Trimmed;
1580
1581 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1582
1583 if (Len == 0) {
1584 return 0;
1585 }
1586
1587 if (Len > NbufQue->BufSize) {
1588 Len = NbufQue->BufSize;
1589 }
1590
1591 NbufQue->BufSize -= Len;
1592 Trimmed = 0;
1593
1594 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
1595 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1596
1597 if (Len >= Nbuf->TotalSize) {
1598 Trimmed += Nbuf->TotalSize;
1599 Len -= Nbuf->TotalSize;
1600
1601 RemoveEntryList (Entry);
1602 NetbufFree (Nbuf);
1603
1604 NbufQue->BufNum--;
1605
1606 if (Len == 0) {
1607 break;
1608 }
1609
1610 } else {
1611 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
1612 break;
1613 }
1614 }
1615
1616 return Trimmed;
1617 }
1618
1619
1620 /**
1621 Flush the net buffer queue.
1622
1623 @param[in, out] NbufQue Pointer to the queue to be flushed.
1624
1625 **/
1626 VOID
1627 EFIAPI
1628 NetbufQueFlush (
1629 IN OUT NET_BUF_QUEUE *NbufQue
1630 )
1631 {
1632 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1633
1634 NetbufFreeList (&NbufQue->BufList);
1635
1636 NbufQue->BufNum = 0;
1637 NbufQue->BufSize = 0;
1638 }
1639
1640
1641 /**
1642 Compute the checksum for a bulk of data.
1643
1644 @param[in] Bulk Pointer to the data.
1645 @param[in] Len Length of the data, in bytes.
1646
1647 @return The computed checksum.
1648
1649 **/
1650 UINT16
1651 EFIAPI
1652 NetblockChecksum (
1653 IN UINT8 *Bulk,
1654 IN UINT32 Len
1655 )
1656 {
1657 register UINT32 Sum;
1658
1659 Sum = 0;
1660
1661 while (Len > 1) {
1662 Sum += *(UINT16 *) Bulk;
1663 Bulk += 2;
1664 Len -= 2;
1665 }
1666
1667 //
1668 // Add left-over byte, if any
1669 //
1670 if (Len > 0) {
1671 Sum += *(UINT8 *) Bulk;
1672 }
1673
1674 //
1675 // Fold 32-bit sum to 16 bits
1676 //
1677 while ((Sum >> 16) != 0) {
1678 Sum = (Sum & 0xffff) + (Sum >> 16);
1679
1680 }
1681
1682 return (UINT16) Sum;
1683 }
1684
1685
1686 /**
1687 Add two checksums.
1688
1689 @param[in] Checksum1 The first checksum to be added.
1690 @param[in] Checksum2 The second checksum to be added.
1691
1692 @return The new checksum.
1693
1694 **/
1695 UINT16
1696 EFIAPI
1697 NetAddChecksum (
1698 IN UINT16 Checksum1,
1699 IN UINT16 Checksum2
1700 )
1701 {
1702 UINT32 Sum;
1703
1704 Sum = Checksum1 + Checksum2;
1705
1706 //
1707 // two UINT16 can only add up to a carry of 1.
1708 //
1709 if ((Sum >> 16) != 0) {
1710 Sum = (Sum & 0xffff) + 1;
1711
1712 }
1713
1714 return (UINT16) Sum;
1715 }
1716
1717
1718 /**
1719 Compute the checksum for a NET_BUF.
1720
1721 @param[in] Nbuf Pointer to the net buffer.
1722
1723 @return The computed checksum.
1724
1725 **/
1726 UINT16
1727 EFIAPI
1728 NetbufChecksum (
1729 IN NET_BUF *Nbuf
1730 )
1731 {
1732 NET_BLOCK_OP *BlockOp;
1733 UINT32 Offset;
1734 UINT16 TotalSum;
1735 UINT16 BlockSum;
1736 UINT32 Index;
1737
1738 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1739
1740 TotalSum = 0;
1741 Offset = 0;
1742 BlockOp = Nbuf->BlockOp;
1743
1744 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1745 if (BlockOp[Index].Size == 0) {
1746 continue;
1747 }
1748
1749 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
1750
1751 if ((Offset & 0x01) != 0) {
1752 //
1753 // The checksum starts with an odd byte, swap
1754 // the checksum before added to total checksum
1755 //
1756 BlockSum = SwapBytes16 (BlockSum);
1757 }
1758
1759 TotalSum = NetAddChecksum (BlockSum, TotalSum);
1760 Offset += BlockOp[Index].Size;
1761 }
1762
1763 return TotalSum;
1764 }
1765
1766
1767 /**
1768 Compute the checksum for TCP/UDP pseudo header.
1769
1770 Src and Dst are in network byte order, and Len is in host byte order.
1771
1772 @param[in] Src The source address of the packet.
1773 @param[in] Dst The destination address of the packet.
1774 @param[in] Proto The protocol type of the packet.
1775 @param[in] Len The length of the packet.
1776
1777 @return The computed checksum.
1778
1779 **/
1780 UINT16
1781 EFIAPI
1782 NetPseudoHeadChecksum (
1783 IN IP4_ADDR Src,
1784 IN IP4_ADDR Dst,
1785 IN UINT8 Proto,
1786 IN UINT16 Len
1787 )
1788 {
1789 NET_PSEUDO_HDR Hdr;
1790
1791 //
1792 // Zero the memory to relieve align problems
1793 //
1794 ZeroMem (&Hdr, sizeof (Hdr));
1795
1796 Hdr.SrcIp = Src;
1797 Hdr.DstIp = Dst;
1798 Hdr.Protocol = Proto;
1799 Hdr.Len = HTONS (Len);
1800
1801 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1802 }
1803
1804 /**
1805 Compute the checksum for TCP6/UDP6 pseudo header.
1806
1807 Src and Dst are in network byte order, and Len is in host byte order.
1808
1809 @param[in] Src The source address of the packet.
1810 @param[in] Dst The destination address of the packet.
1811 @param[in] NextHeader The protocol type of the packet.
1812 @param[in] Len The length of the packet.
1813
1814 @return The computed checksum.
1815
1816 **/
1817 UINT16
1818 NetIp6PseudoHeadChecksum (
1819 IN EFI_IPv6_ADDRESS *Src,
1820 IN EFI_IPv6_ADDRESS *Dst,
1821 IN UINT8 NextHeader,
1822 IN UINT32 Len
1823 )
1824 {
1825 NET_IP6_PSEUDO_HDR Hdr;
1826
1827 //
1828 // Zero the memory to relieve align problems
1829 //
1830 ZeroMem (&Hdr, sizeof (Hdr));
1831
1832 IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);
1833 IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);
1834
1835 Hdr.NextHeader = NextHeader;
1836 Hdr.Len = HTONL (Len);
1837
1838 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1839 }
1840