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