2 Network library functions providing net buffer operation support.
4 Copyright (c) 2005 - 2006, 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
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.
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>
25 Allocate and build up the sketch for a NET_BUF.
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.
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
34 @return Pointer to the allocated NET_BUF, or NULL if the
35 allocation failed due to resource limit.
47 ASSERT (BlockOpNum
>= 1);
50 // Allocate three memory blocks.
52 Nbuf
= AllocateZeroPool (NET_BUF_SIZE (BlockOpNum
));
58 Nbuf
->Signature
= NET_BUF_SIGNATURE
;
60 Nbuf
->BlockOpNum
= BlockOpNum
;
61 InitializeListHead (&Nbuf
->List
);
64 Vector
= AllocateZeroPool (NET_VECTOR_SIZE (BlockNum
));
70 Vector
->Signature
= NET_VECTOR_SIGNATURE
;
72 Vector
->BlockNum
= BlockNum
;
73 Nbuf
->Vector
= Vector
;
86 Allocate a single block NET_BUF. Upon allocation, all the
87 free space is in the tail room.
89 @param[in] Len The length of the block.
91 @return Pointer to the allocated NET_BUF, or NULL if the
92 allocation failed due to resource limit.
107 Nbuf
= NetbufAllocStruct (1, 1);
113 Bulk
= AllocatePool (Len
);
119 Vector
= Nbuf
->Vector
;
122 Vector
->Block
[0].Bulk
= Bulk
;
123 Vector
->Block
[0].Len
= Len
;
125 Nbuf
->BlockOp
[0].BlockHead
= Bulk
;
126 Nbuf
->BlockOp
[0].BlockTail
= Bulk
+ Len
;
128 Nbuf
->BlockOp
[0].Head
= Bulk
;
129 Nbuf
->BlockOp
[0].Tail
= Bulk
;
130 Nbuf
->BlockOp
[0].Size
= 0;
135 gBS
->FreePool (Nbuf
);
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
146 @param[in] Vector Pointer to the NET_VECTOR to be freed.
151 IN NET_VECTOR
*Vector
156 NET_CHECK_SIGNATURE (Vector
, NET_VECTOR_SIGNATURE
);
157 ASSERT (Vector
->RefCnt
> 0);
161 if (Vector
->RefCnt
> 0) {
165 if (Vector
->Free
!= NULL
) {
167 // Call external free function to free the vector if it
168 // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
169 // first block since it is allocated by us
171 if ((Vector
->Flag
& NET_VECTOR_OWN_FIRST
) != 0) {
172 gBS
->FreePool (Vector
->Block
[0].Bulk
);
175 Vector
->Free (Vector
->Arg
);
179 // Free each memory block associated with the Vector
181 for (Index
= 0; Index
< Vector
->BlockNum
; Index
++) {
182 gBS
->FreePool (Vector
->Block
[Index
].Bulk
);
186 gBS
->FreePool (Vector
);
191 Free the net buffer and its associated NET_VECTOR.
193 Decrease the reference count of the net buffer by one. Free the associated net
194 vector and itself if the reference count of the net buffer is decreased to 0.
195 The net vector free operation just decrease the reference count of the net
196 vector by one and do the real resource free operation when the reference count
197 of the net vector is 0.
199 @param[in] Nbuf Pointer to the NET_BUF to be freed.
208 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
209 ASSERT (Nbuf
->RefCnt
> 0);
213 if (Nbuf
->RefCnt
== 0) {
215 // Update Vector only when NBuf is to be released. That is,
216 // all the sharing of Nbuf increse Vector's RefCnt by one
218 NetbufFreeVector (Nbuf
->Vector
);
219 gBS
->FreePool (Nbuf
);
225 Create a copy of the net buffer that shares the associated net vector.
227 The reference count of the newly created net buffer is set to 1. The reference
228 count of the associated net vector is increased by one.
230 @param[in] Nbuf Pointer to the net buffer to be cloned.
232 @return Pointer to the cloned net buffer, or NULL if the
233 allocation failed due to resource limit.
244 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
246 Clone
= AllocatePool (NET_BUF_SIZE (Nbuf
->BlockOpNum
));
252 Clone
->Signature
= NET_BUF_SIGNATURE
;
254 InitializeListHead (&Clone
->List
);
256 Clone
->Ip
= Nbuf
->Ip
;
257 Clone
->Tcp
= Nbuf
->Tcp
;
259 CopyMem (Clone
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
261 NET_GET_REF (Nbuf
->Vector
);
263 Clone
->Vector
= Nbuf
->Vector
;
264 Clone
->BlockOpNum
= Nbuf
->BlockOpNum
;
265 Clone
->TotalSize
= Nbuf
->TotalSize
;
266 CopyMem (Clone
->BlockOp
, Nbuf
->BlockOp
, sizeof (NET_BLOCK_OP
) * Nbuf
->BlockOpNum
);
273 Create a duplicated copy of the net buffer with data copied and HeadSpace
274 bytes of head space reserved.
276 The duplicated net buffer will allocate its own memory to hold the data of the
279 @param[in] Nbuf Pointer to the net buffer to be duplicated from.
280 @param[in, out] Duplicate Pointer to the net buffer to duplicate to, if
281 NULL a new net buffer is allocated.
282 @param[in] HeadSpace Length of the head space to reserve.
284 @return Pointer to the duplicated net buffer, or NULL if
285 the allocation failed due to resource limit.
292 IN OUT NET_BUF
*Duplicate OPTIONAL
,
298 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
300 if (Duplicate
== NULL
) {
301 Duplicate
= NetbufAlloc (Nbuf
->TotalSize
+ HeadSpace
);
304 if (Duplicate
== NULL
) {
309 // Don't set the IP and TCP head point, since it is most
310 // like that they are pointing to the memory of Nbuf.
312 CopyMem (Duplicate
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
313 NetbufReserve (Duplicate
, HeadSpace
);
315 Dst
= NetbufAllocSpace (Duplicate
, Nbuf
->TotalSize
, NET_BUF_TAIL
);
316 NetbufCopy (Nbuf
, 0, Nbuf
->TotalSize
, Dst
);
323 Free a list of net buffers.
325 @param[in, out] Head Pointer to the head of linked net buffers.
331 IN OUT LIST_ENTRY
*Head
338 Entry
= Head
->ForwardLink
;
340 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
341 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
342 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
344 RemoveEntryList (Entry
);
348 ASSERT (IsListEmpty (Head
));
353 Get the index of NET_BLOCK_OP that contains the byte at Offset in the net
356 This can be used to, for example, retrieve the IP header in the packet. It
357 also can be used to get the fragment that contains the byte which is used
358 mainly by the library implementation itself.
360 @param[in] Nbuf Pointer to the net buffer.
361 @param[in] Offset The offset of the byte.
362 @param[out] Index Index of the NET_BLOCK_OP that contains the byte at
365 @return Pointer to the Offset'th byte of data in the net buffer, or NULL
366 if there is no such data in the net buffer.
374 OUT UINT32
*Index OPTIONAL
377 NET_BLOCK_OP
*BlockOp
;
381 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
383 if (Offset
>= Nbuf
->TotalSize
) {
387 BlockOp
= Nbuf
->BlockOp
;
390 for (Loop
= 0; Loop
< Nbuf
->BlockOpNum
; Loop
++) {
392 if (Len
+ BlockOp
[Loop
].Size
<= Offset
) {
393 Len
+= BlockOp
[Loop
].Size
;
401 return BlockOp
[Loop
].Head
+ (Offset
- Len
);
410 Set the NET_BLOCK and corresponding NET_BLOCK_OP in the net buffer and
411 corresponding net vector according to the bulk pointer and bulk length.
413 All the pointers in the Index'th NET_BLOCK and NET_BLOCK_OP are set to the
414 bulk's head and tail respectively. So, this function alone can't be used by
417 @param[in, out] Nbuf Pointer to the net buffer.
418 @param[in] Bulk Pointer to the data.
419 @param[in] Len Length of the bulk data.
420 @param[in] Index The data block index in the net buffer the bulk
421 data should belong to.
426 IN OUT NET_BUF
*Nbuf
,
432 NET_BLOCK_OP
*BlockOp
;
435 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
436 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
437 ASSERT (Index
< Nbuf
->BlockOpNum
);
439 Block
= &(Nbuf
->Vector
->Block
[Index
]);
440 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
443 BlockOp
->BlockHead
= Bulk
;
444 BlockOp
->BlockTail
= Bulk
+ Len
;
445 BlockOp
->Head
= Bulk
;
446 BlockOp
->Tail
= Bulk
+ Len
;
453 Set the NET_BLOCK_OP in the net buffer. The corresponding NET_BLOCK
454 structure is left untouched.
456 Some times, there is no 1:1 relationship between NET_BLOCK and NET_BLOCK_OP.
457 For example, that in NetbufGetFragment.
459 @param[in, out] Nbuf Pointer to the net buffer.
460 @param[in] Bulk Pointer to the data.
461 @param[in] Len Length of the bulk data.
462 @param[in] Index The data block index in the net buffer the bulk
463 data should belong to.
468 IN OUT NET_BUF
*Nbuf
,
474 NET_BLOCK_OP
*BlockOp
;
476 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
477 ASSERT (Index
< Nbuf
->BlockOpNum
);
479 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
480 BlockOp
->BlockHead
= Bulk
;
481 BlockOp
->BlockTail
= Bulk
+ Len
;
482 BlockOp
->Head
= Bulk
;
483 BlockOp
->Tail
= Bulk
+ Len
;
489 Helper function for NetbufGetFragment. NetbufGetFragment may allocate the
490 first block to reserve HeadSpace bytes header space. So it needs to create a
491 new net vector for the first block and can avoid copy for the remaining data
492 by sharing the old net vector.
494 @param[in] Arg Point to the old NET_VECTOR.
498 NetbufGetFragmentFree (
504 Vector
= (NET_VECTOR
*)Arg
;
505 NetbufFreeVector (Vector
);
511 Create a NET_BUF structure which contains Len byte data of Nbuf starting from
514 A new NET_BUF structure will be created but the associated data in NET_VECTOR
515 is shared. This function exists to do IP packet fragmentation.
517 @param[in] Nbuf Pointer to the net buffer to be extracted.
518 @param[in] Offset Starting point of the data to be included in the new
520 @param[in] Len Bytes of data to be included in the new net buffer.
521 @param[in] HeadSpace Bytes of head space to reserve for protocol header.
523 @return Pointer to the cloned net buffer, or NULL if the
524 allocation failed due to resource limit.
538 NET_BLOCK_OP
*BlockOp
;
550 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
552 if ((Len
== 0) || (Offset
+ Len
> Nbuf
->TotalSize
)) {
557 // First find the first and last BlockOp that contains
558 // the valid data, and compute the offset of the first
559 // BlockOp and length of the last BlockOp
561 BlockOp
= Nbuf
->BlockOp
;
564 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
565 if (Offset
< Cur
+ BlockOp
[Index
].Size
) {
569 Cur
+= BlockOp
[Index
].Size
;
573 // First is the index of the first BlockOp, FirstSkip is
574 // the offset of the first byte in the first BlockOp.
577 FirstSkip
= Offset
- Cur
;
578 FirstLen
= BlockOp
[Index
].Size
- FirstSkip
;
581 //redundant assignment to make compiler happy.
586 if (Len
> FirstLen
) {
587 Cur
+= BlockOp
[Index
].Size
;
590 for (; Index
< Nbuf
->BlockOpNum
; Index
++) {
591 if (Offset
+ Len
<= Cur
+ BlockOp
[Index
].Size
) {
593 LastLen
= Offset
+ Len
- Cur
;
597 Cur
+= BlockOp
[Index
].Size
;
606 BlockOpNum
= Last
- First
+ 1;
609 if (HeadSpace
!= 0) {
611 // Allocate an extra block to accomdate the head space.
615 Child
= NetbufAllocStruct (1, BlockOpNum
);
621 FirstBulk
= AllocatePool (HeadSpace
);
623 if (FirstBulk
== NULL
) {
627 Vector
= Child
->Vector
;
628 Vector
->Free
= NetbufGetFragmentFree
;
629 Vector
->Arg
= Nbuf
->Vector
;
630 Vector
->Flag
= NET_VECTOR_OWN_FIRST
;
631 Vector
->Len
= HeadSpace
;
634 // Reserve the head space in the first block
636 NetbufSetBlock (Child
, FirstBulk
, HeadSpace
, 0);
637 Child
->BlockOp
[0].Head
+= HeadSpace
;
638 Child
->BlockOp
[0].Size
= 0;
642 Child
= NetbufAllocStruct (0, BlockOpNum
);
648 Child
->Vector
= Nbuf
->Vector
;
651 NET_GET_REF (Nbuf
->Vector
);
652 Child
->TotalSize
= Len
;
655 // Set all the BlockOp up, the first and last one are special
656 // and need special process.
660 Nbuf
->BlockOp
[First
].Head
+ FirstSkip
,
665 for (Index
= First
+ 1; Index
<= Last
- 1 ; Index
++) {
683 CopyMem (Child
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
688 gBS
->FreePool (Child
);
695 Build a NET_BUF from external blocks.
697 A new NET_BUF structure will be created from external blocks. Additional block
698 of memory will be allocated to hold reserved HeadSpace bytes of header room
699 and existing HeadLen bytes of header but the external blocks are shared by the
700 net buffer to avoid data copying.
702 @param[in] ExtFragment Pointer to the data block.
703 @param[in] ExtNum The number of the data blocks.
704 @param[in] HeadSpace The head space to be reserved.
705 @param[in] HeadLen The length of the protocol header, This function
706 will pull that number of data into a linear block.
707 @param[in] ExtFree Pointer to the caller provided free function.
708 @param[in] Arg The argument passed to ExtFree when ExtFree is
711 @return Pointer to the net buffer built from the data blocks,
712 or NULL if the allocation failed due to resource
719 IN NET_FRAGMENT
*ExtFragment
,
723 IN NET_VECTOR_EXT_FREE ExtFree
,
724 IN VOID
*Arg OPTIONAL
729 NET_FRAGMENT SavedFragment
;
734 UINT32 FirstBlockLen
;
741 ASSERT ((ExtFragment
!= NULL
) && (ExtNum
> 0) && (ExtFree
!= NULL
));
743 SavedFragment
.Bulk
= NULL
;
744 SavedFragment
.Len
= 0;
756 // No need to consolidate the header if the first block is
757 // longer than the header length or there is only one block.
759 if ((ExtFragment
[0].Len
>= HeadLen
) || (ExtNum
== 1)) {
764 // Allocate an extra block if we need to:
765 // 1. Allocate some header space
766 // 2. aggreate the packet header
768 if ((HeadSpace
!= 0) || (HeadLen
!= 0)) {
769 FirstBlockLen
= HeadLen
+ HeadSpace
;
770 FirstBlock
= AllocatePool (FirstBlockLen
);
772 if (FirstBlock
== NULL
) {
780 // Copy the header to the first block, reduce the NET_BLOCK
781 // to allocate by one for each block that is completely covered
782 // by the first bulk.
786 Header
= FirstBlock
+ HeadSpace
;
788 for (Index
= 0; Index
< ExtNum
; Index
++) {
789 if (Len
>= ExtFragment
[Index
].Len
) {
790 CopyMem (Header
, ExtFragment
[Index
].Bulk
, ExtFragment
[Index
].Len
);
792 Copied
+= ExtFragment
[Index
].Len
;
793 Len
-= ExtFragment
[Index
].Len
;
794 Header
+= ExtFragment
[Index
].Len
;
795 TotalLen
+= ExtFragment
[Index
].Len
;
800 // Increament the index number to point to the next
801 // non-empty fragment.
808 CopyMem (Header
, ExtFragment
[Index
].Bulk
, Len
);
814 // Adjust the block structure to exclude the data copied,
815 // So, the left-over block can be processed as other blocks.
816 // But it must be recovered later. (SavedIndex > 0) always
817 // holds since we don't aggreate the header if the first block
818 // is bigger enough that the header is continuous
821 SavedFragment
= ExtFragment
[Index
];
822 ExtFragment
[Index
].Bulk
+= Len
;
823 ExtFragment
[Index
].Len
-= Len
;
829 Nbuf
= NetbufAllocStruct (BlockNum
, BlockNum
);
835 Vector
= Nbuf
->Vector
;
836 Vector
->Free
= ExtFree
;
838 Vector
->Flag
= ((FirstBlockLen
!= 0) ? NET_VECTOR_OWN_FIRST
: 0);
841 // Set the first block up which may contain
842 // some head space and aggregated header
846 if (FirstBlockLen
!= 0) {
847 NetbufSetBlock (Nbuf
, FirstBlock
, HeadSpace
+ Copied
, 0);
848 Nbuf
->BlockOp
[0].Head
+= HeadSpace
;
849 Nbuf
->BlockOp
[0].Size
= Copied
;
854 for (; Index
< ExtNum
; Index
++) {
855 NetbufSetBlock (Nbuf
, ExtFragment
[Index
].Bulk
, ExtFragment
[Index
].Len
, CurBlock
);
856 TotalLen
+= ExtFragment
[Index
].Len
;
860 Vector
->Len
= TotalLen
+ HeadSpace
;
861 Nbuf
->TotalSize
= TotalLen
;
863 if (SavedIndex
!= 0) {
864 ExtFragment
[SavedIndex
] = SavedFragment
;
870 gBS
->FreePool (FirstBlock
);
876 Build a fragment table to contain the fragments in the net buffer. This is the
877 opposite operation of the NetbufFromExt.
879 @param[in] Nbuf Point to the net buffer.
880 @param[in, out] ExtFragment Pointer to the data block.
881 @param[in, out] ExtNum The number of the data blocks.
883 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than
885 @retval EFI_SUCCESS Fragment table is built successfully.
892 IN OUT NET_FRAGMENT
*ExtFragment
,
893 IN OUT UINT32
*ExtNum
901 for (Index
= 0; (Index
< Nbuf
->BlockOpNum
); Index
++) {
902 if (Nbuf
->BlockOp
[Index
].Size
== 0) {
906 if (Current
< *ExtNum
) {
907 ExtFragment
[Current
].Bulk
= Nbuf
->BlockOp
[Index
].Head
;
908 ExtFragment
[Current
].Len
= Nbuf
->BlockOp
[Index
].Size
;
911 return EFI_BUFFER_TOO_SMALL
;
921 Build a net buffer from a list of net buffers.
923 All the fragments will be collected from the list of NEW_BUF and then a new
924 net buffer will be created through NetbufFromExt.
926 @param[in] BufList A List of the net buffer.
927 @param[in] HeadSpace The head space to be reserved.
928 @param[in] HeaderLen The length of the protocol header, This function
929 will pull that number of data into a linear block.
930 @param[in] ExtFree Pointer to the caller provided free function.
931 @param[in] Arg The argument passed to ExtFree when ExtFree is called.
933 @return Pointer to the net buffer built from the list of net
940 IN LIST_ENTRY
*BufList
,
943 IN NET_VECTOR_EXT_FREE ExtFree
,
944 IN VOID
*Arg OPTIONAL
947 NET_FRAGMENT
*Fragment
;
955 //Compute how many blocks are there
959 NET_LIST_FOR_EACH (Entry
, BufList
) {
960 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
961 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
962 FragmentNum
+= Nbuf
->BlockOpNum
;
966 //Allocate and copy block points
968 Fragment
= AllocatePool (sizeof (NET_FRAGMENT
) * FragmentNum
);
970 if (Fragment
== NULL
) {
976 NET_LIST_FOR_EACH (Entry
, BufList
) {
977 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
978 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
980 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
981 if (Nbuf
->BlockOp
[Index
].Size
!= 0) {
982 Fragment
[Current
].Bulk
= Nbuf
->BlockOp
[Index
].Head
;
983 Fragment
[Current
].Len
= Nbuf
->BlockOp
[Index
].Size
;
989 Nbuf
= NetbufFromExt (Fragment
, Current
, HeadSpace
, HeaderLen
, ExtFree
, Arg
);
990 gBS
->FreePool (Fragment
);
997 Reserve some space in the header room of the net buffer.
999 Upon allocation, all the space are in the tail room of the buffer. Call this
1000 function to move some space to the header room. This function is quite limited
1001 in that it can only reserve space from the first block of an empty NET_BUF not
1002 built from the external. But it should be enough for the network stack.
1004 @param[in, out] Nbuf Pointer to the net buffer.
1005 @param[in] Len The length of buffer to be reserved from the header.
1011 IN OUT NET_BUF
*Nbuf
,
1015 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1016 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
1018 ASSERT ((Nbuf
->BlockOpNum
== 1) && (Nbuf
->TotalSize
== 0));
1019 ASSERT ((Nbuf
->Vector
->Free
== NULL
) && (Nbuf
->Vector
->Len
>= Len
));
1021 Nbuf
->BlockOp
[0].Head
+= Len
;
1022 Nbuf
->BlockOp
[0].Tail
+= Len
;
1024 ASSERT (Nbuf
->BlockOp
[0].Tail
<= Nbuf
->BlockOp
[0].BlockTail
);
1029 Allocate Len bytes of space from the header or tail of the buffer.
1031 @param[in, out] Nbuf Pointer to the net buffer.
1032 @param[in] Len The length of the buffer to be allocated.
1033 @param[in] FromHead The flag to indicate whether reserve the data
1034 from head (TRUE) or tail (FALSE).
1036 @return Pointer to the first byte of the allocated buffer,
1037 or NULL if there is no sufficient space.
1043 IN OUT NET_BUF
*Nbuf
,
1048 NET_BLOCK_OP
*BlockOp
;
1052 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1053 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
1059 // Allocate some space from head. If the buffer is empty,
1060 // allocate from the first block. If it isn't, allocate
1061 // from the first non-empty block, or the block before that.
1063 if (Nbuf
->TotalSize
== 0) {
1066 NetbufGetByte (Nbuf
, 0, &Index
);
1068 if ((NET_HEADSPACE(&(Nbuf
->BlockOp
[Index
])) < Len
) && (Index
> 0)) {
1073 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
1075 if (NET_HEADSPACE (BlockOp
) < Len
) {
1079 BlockOp
->Head
-= Len
;
1080 BlockOp
->Size
+= Len
;
1081 Nbuf
->TotalSize
+= Len
;
1083 return BlockOp
->Head
;
1087 // Allocate some space from the tail. If the buffer is empty,
1088 // allocate from the first block. If it isn't, allocate
1089 // from the last non-empty block, or the block after that.
1091 if (Nbuf
->TotalSize
== 0) {
1094 NetbufGetByte (Nbuf
, Nbuf
->TotalSize
- 1, &Index
);
1096 if ((NET_TAILSPACE(&(Nbuf
->BlockOp
[Index
])) < Len
) &&
1097 (Index
< Nbuf
->BlockOpNum
- 1)) {
1103 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
1105 if (NET_TAILSPACE (BlockOp
) < Len
) {
1109 SavedTail
= BlockOp
->Tail
;
1111 BlockOp
->Tail
+= Len
;
1112 BlockOp
->Size
+= Len
;
1113 Nbuf
->TotalSize
+= Len
;
1121 Trim a single NET_BLOCK by Len bytes from the header or tail.
1123 @param[in, out] BlockOp Pointer to the NET_BLOCK.
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).
1131 IN OUT NET_BLOCK_OP
*BlockOp
,
1136 ASSERT ((BlockOp
!= NULL
) && (BlockOp
->Size
>= Len
));
1138 BlockOp
->Size
-= Len
;
1141 BlockOp
->Head
+= Len
;
1143 BlockOp
->Tail
-= Len
;
1149 Trim Len bytes from the header or tail of the net buffer.
1151 @param[in, out] Nbuf Pointer to the net buffer.
1152 @param[in] Len The length of the data to be trimmed.
1153 @param[in] FromHead The flag to indicate whether trim data from head
1154 (TRUE) or tail (FALSE).
1156 @return Length of the actually trimmed data, which is possible to be less
1157 than Len because the TotalSize of Nbuf is less than Len.
1163 IN OUT NET_BUF
*Nbuf
,
1168 NET_BLOCK_OP
*BlockOp
;
1172 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1174 if (Len
> Nbuf
->TotalSize
) {
1175 Len
= Nbuf
->TotalSize
;
1179 // If FromTail is true, iterate backward. That
1180 // is, init Index to NBuf->BlockNum - 1, and
1181 // decrease it by 1 during each loop. Otherwise,
1182 // iterate forward. That is, init Index to 0, and
1183 // increase it by 1 during each loop.
1186 Nbuf
->TotalSize
-= Len
;
1188 Index
= (FromHead
? 0 : Nbuf
->BlockOpNum
- 1);
1189 BlockOp
= Nbuf
->BlockOp
;
1192 if (BlockOp
[Index
].Size
== 0) {
1193 Index
+= (FromHead
? 1 : -1);
1197 if (Len
> BlockOp
[Index
].Size
) {
1198 Len
-= BlockOp
[Index
].Size
;
1199 Trimmed
+= BlockOp
[Index
].Size
;
1200 NetblockTrim (&BlockOp
[Index
], BlockOp
[Index
].Size
, FromHead
);
1203 NetblockTrim (&BlockOp
[Index
], Len
, FromHead
);
1207 Index
+= (FromHead
? 1 : -1);
1215 Copy Len bytes of data from the specific offset of the net buffer to the
1218 The Len bytes of data may cross the several fragments of the net buffer.
1220 @param[in] Nbuf Pointer to the net buffer.
1221 @param[in] Offset The sequence number of the first byte to copy.
1222 @param[in] Len Length of the data to copy.
1223 @param[in] Dest The destination of the data to copy to.
1225 @return The length of the actual copied data, or 0 if the offset
1226 specified exceeds the total size of net buffer.
1238 NET_BLOCK_OP
*BlockOp
;
1245 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1248 if ((Len
== 0) || (Nbuf
->TotalSize
<= Offset
)) {
1252 if (Nbuf
->TotalSize
- Offset
< Len
) {
1253 Len
= Nbuf
->TotalSize
- Offset
;
1256 BlockOp
= Nbuf
->BlockOp
;
1259 // Skip to the offset. Don't make "Offset-By-One" error here.
1260 // Cur + BLOCK.SIZE is the first sequence number of next block.
1261 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
1262 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
1263 // first byte is the next block's first byte.
1267 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
1268 if (BlockOp
[Index
].Size
== 0) {
1272 if (Offset
< Cur
+ BlockOp
[Index
].Size
) {
1276 Cur
+= BlockOp
[Index
].Size
;
1280 // Cur is the sequence number of the first byte in the block
1281 // Offset - Cur is the number of bytes before first byte to
1282 // to copy in the current block.
1284 Skip
= Offset
- Cur
;
1285 Left
= BlockOp
[Index
].Size
- Skip
;
1288 CopyMem (Dest
, BlockOp
[Index
].Head
+ Skip
, Len
);
1292 CopyMem (Dest
, BlockOp
[Index
].Head
+ Skip
, Left
);
1300 for (; Index
< Nbuf
->BlockOpNum
; Index
++) {
1301 if (Len
> BlockOp
[Index
].Size
) {
1302 Len
-= BlockOp
[Index
].Size
;
1303 Copied
+= BlockOp
[Index
].Size
;
1305 CopyMem (Dest
, BlockOp
[Index
].Head
, BlockOp
[Index
].Size
);
1306 Dest
+= BlockOp
[Index
].Size
;
1309 CopyMem (Dest
, BlockOp
[Index
].Head
, Len
);
1319 Initiate the net buffer queue.
1321 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.
1327 IN OUT NET_BUF_QUEUE
*NbufQue
1330 NbufQue
->Signature
= NET_QUE_SIGNATURE
;
1331 NbufQue
->RefCnt
= 1;
1332 InitializeListHead (&NbufQue
->List
);
1334 InitializeListHead (&NbufQue
->BufList
);
1335 NbufQue
->BufSize
= 0;
1336 NbufQue
->BufNum
= 0;
1341 Allocate and initialize a net buffer queue.
1343 @return Pointer to the allocated net buffer queue, or NULL if the
1344 allocation failed due to resource limit.
1353 NET_BUF_QUEUE
*NbufQue
;
1355 NbufQue
= AllocatePool (sizeof (NET_BUF_QUEUE
));
1356 if (NbufQue
== NULL
) {
1360 NetbufQueInit (NbufQue
);
1367 Free a net buffer queue.
1369 Decrease the reference count of the net buffer queue by one. The real resource
1370 free operation isn't performed until the reference count of the net buffer
1371 queue is decreased to 0.
1373 @param[in] NbufQue Pointer to the net buffer queue to be freed.
1379 IN NET_BUF_QUEUE
*NbufQue
1382 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1386 if (NbufQue
->RefCnt
== 0) {
1387 NetbufQueFlush (NbufQue
);
1388 gBS
->FreePool (NbufQue
);
1394 Append a net buffer to the net buffer queue.
1396 @param[in, out] NbufQue Pointer to the net buffer queue.
1397 @param[in, out] Nbuf Pointer to the net buffer to be appended.
1403 IN OUT NET_BUF_QUEUE
*NbufQue
,
1404 IN OUT NET_BUF
*Nbuf
1407 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1408 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1410 InsertTailList (&NbufQue
->BufList
, &Nbuf
->List
);
1412 NbufQue
->BufSize
+= Nbuf
->TotalSize
;
1418 Remove a net buffer from the head in the specific queue and return it.
1420 @param[in, out] NbufQue Pointer to the net buffer queue.
1422 @return Pointer to the net buffer removed from the specific queue,
1423 or NULL if there is no net buffer in the specific queue.
1429 IN OUT NET_BUF_QUEUE
*NbufQue
1434 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1436 if (NbufQue
->BufNum
== 0) {
1440 First
= NET_LIST_USER_STRUCT (NbufQue
->BufList
.ForwardLink
, NET_BUF
, List
);
1442 NetListRemoveHead (&NbufQue
->BufList
);
1444 NbufQue
->BufSize
-= First
->TotalSize
;
1451 Copy Len bytes of data from the net buffer queue at the specific offset to the
1454 The copying operation is the same as NetbufCopy but applies to the net buffer
1455 queue instead of the net buffer.
1457 @param[in] NbufQue Pointer to the net buffer queue.
1458 @param[in] Offset The sequence number of the first byte to copy.
1459 @param[in] Len Length of the data to copy.
1460 @param[out] Dest The destination of the data to copy to.
1462 @return The length of the actual copied data, or 0 if the offset
1463 specified exceeds the total size of net buffer queue.
1469 IN NET_BUF_QUEUE
*NbufQue
,
1482 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1483 ASSERT (Dest
!= NULL
);
1485 if ((Len
== 0) || (NbufQue
->BufSize
<= Offset
)) {
1489 if (NbufQue
->BufSize
- Offset
< Len
) {
1490 Len
= NbufQue
->BufSize
- Offset
;
1494 // skip to the Offset
1499 NET_LIST_FOR_EACH (Entry
, &NbufQue
->BufList
) {
1500 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1502 if (Offset
< Cur
+ Nbuf
->TotalSize
) {
1506 Cur
+= Nbuf
->TotalSize
;
1510 // Copy the data in the first buffer.
1512 Skip
= Offset
- Cur
;
1513 Left
= Nbuf
->TotalSize
- Skip
;
1516 return NetbufCopy (Nbuf
, Skip
, Len
, Dest
);
1519 NetbufCopy (Nbuf
, Skip
, Left
, Dest
);
1525 // Iterate over the others
1527 Entry
= Entry
->ForwardLink
;
1529 while ((Len
> 0) && (Entry
!= &NbufQue
->BufList
)) {
1530 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1532 if (Len
> Nbuf
->TotalSize
) {
1533 Len
-= Nbuf
->TotalSize
;
1534 Copied
+= Nbuf
->TotalSize
;
1536 NetbufCopy (Nbuf
, 0, Nbuf
->TotalSize
, Dest
);
1537 Dest
+= Nbuf
->TotalSize
;
1540 NetbufCopy (Nbuf
, 0, Len
, Dest
);
1545 Entry
= Entry
->ForwardLink
;
1553 Trim Len bytes of data from the queue header, release any of the net buffer
1554 whom is trimmed wholely.
1556 The trimming operation is the same as NetbufTrim but applies to the net buffer
1557 queue instead of the net buffer.
1559 @param[in, out] NbufQue Pointer to the net buffer queue.
1560 @param[in] Len Length of the data to trim.
1562 @return The actual length of the data trimmed.
1568 IN OUT NET_BUF_QUEUE
*NbufQue
,
1577 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1583 if (Len
> NbufQue
->BufSize
) {
1584 Len
= NbufQue
->BufSize
;
1587 NbufQue
->BufSize
-= Len
;
1590 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &NbufQue
->BufList
) {
1591 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1593 if (Len
>= Nbuf
->TotalSize
) {
1594 Trimmed
+= Nbuf
->TotalSize
;
1595 Len
-= Nbuf
->TotalSize
;
1597 RemoveEntryList (Entry
);
1607 Trimmed
+= NetbufTrim (Nbuf
, Len
, NET_BUF_HEAD
);
1617 Flush the net buffer queue.
1619 @param[in, out] NbufQue Pointer to the queue to be flushed.
1625 IN OUT NET_BUF_QUEUE
*NbufQue
1628 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1630 NetbufFreeList (&NbufQue
->BufList
);
1632 NbufQue
->BufNum
= 0;
1633 NbufQue
->BufSize
= 0;
1638 Compute the checksum for a bulk of data.
1640 @param[in] Bulk Pointer to the data.
1641 @param[in] Len Length of the data, in bytes.
1643 @return The computed checksum.
1653 register UINT32 Sum
;
1658 Sum
+= *(UINT16
*) Bulk
;
1664 // Add left-over byte, if any
1667 Sum
+= *(UINT8
*) Bulk
;
1671 // Fold 32-bit sum to 16 bits
1673 while ((Sum
>> 16) != 0) {
1674 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
1678 return (UINT16
) Sum
;
1685 @param[in] Checksum1 The first checksum to be added.
1686 @param[in] Checksum2 The second checksum to be added.
1688 @return The new checksum.
1694 IN UINT16 Checksum1
,
1700 Sum
= Checksum1
+ Checksum2
;
1703 // two UINT16 can only add up to a carry of 1.
1705 if ((Sum
>> 16) != 0) {
1706 Sum
= (Sum
& 0xffff) + 1;
1710 return (UINT16
) Sum
;
1715 Compute the checksum for a NET_BUF.
1717 @param[in] Nbuf Pointer to the net buffer.
1719 @return The computed checksum.
1728 NET_BLOCK_OP
*BlockOp
;
1734 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1738 BlockOp
= Nbuf
->BlockOp
;
1740 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
1741 if (BlockOp
[Index
].Size
== 0) {
1745 BlockSum
= NetblockChecksum (BlockOp
[Index
].Head
, BlockOp
[Index
].Size
);
1747 if ((Offset
& 0x01) != 0) {
1749 // The checksum starts with an odd byte, swap
1750 // the checksum before added to total checksum
1752 BlockSum
= (UINT16
) NET_SWAP_SHORT (BlockSum
);
1755 TotalSum
= NetAddChecksum (BlockSum
, TotalSum
);
1756 Offset
+= BlockOp
[Index
].Size
;
1764 Compute the checksum for TCP/UDP pseudo header.
1766 Src and Dst are in network byte order, and Len is in host byte order.
1768 @param[in] Src The source address of the packet.
1769 @param[in] Dst The destination address of the packet.
1770 @param[in] Proto The protocol type of the packet.
1771 @param[in] Len The length of the packet.
1773 @return The computed checksum.
1778 NetPseudoHeadChecksum (
1788 // Zero the memory to relieve align problems
1790 ZeroMem (&Hdr
, sizeof (Hdr
));
1794 Hdr
.Protocol
= Proto
;
1795 Hdr
.Len
= HTONS (Len
);
1797 return NetblockChecksum ((UINT8
*) &Hdr
, sizeof (Hdr
));