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. The net buffer allocated
26 has the BlockOpNum's NET_BLOCK_OP, and its associated NET_VECTOR has the
29 @param[in] BlockNum The number of NET_BLOCK in the Vector of net buffer
30 @param[in] BlockOpNum The number of NET_BLOCK_OP in the net buffer
32 @return Pointer to the allocated NET_BUF. If NULL, the
33 allocation failed due to resource limit.
45 ASSERT (BlockOpNum
>= 1);
48 // Allocate three memory blocks.
50 Nbuf
= AllocateZeroPool (NET_BUF_SIZE (BlockOpNum
));
56 Nbuf
->Signature
= NET_BUF_SIGNATURE
;
58 Nbuf
->BlockOpNum
= BlockOpNum
;
59 InitializeListHead (&Nbuf
->List
);
62 Vector
= AllocateZeroPool (NET_VECTOR_SIZE (BlockNum
));
68 Vector
->Signature
= NET_VECTOR_SIGNATURE
;
70 Vector
->BlockNum
= BlockNum
;
71 Nbuf
->Vector
= Vector
;
84 Allocate a single block NET_BUF. Upon allocation, all the
85 free space is in the tail room.
87 @param[in] Len The length of the block.
89 @return Pointer to the allocated NET_BUF. If NULL the
90 allocation failed due to resource limit.
105 Nbuf
= NetbufAllocStruct (1, 1);
111 Bulk
= AllocatePool (Len
);
117 Vector
= Nbuf
->Vector
;
120 Vector
->Block
[0].Bulk
= Bulk
;
121 Vector
->Block
[0].Len
= Len
;
123 Nbuf
->BlockOp
[0].BlockHead
= Bulk
;
124 Nbuf
->BlockOp
[0].BlockTail
= Bulk
+ Len
;
126 Nbuf
->BlockOp
[0].Head
= Bulk
;
127 Nbuf
->BlockOp
[0].Tail
= Bulk
;
128 Nbuf
->BlockOp
[0].Size
= 0;
133 gBS
->FreePool (Nbuf
);
141 @param[in] Vector Pointer to the NET_VECTOR to be freed.
146 IN NET_VECTOR
*Vector
151 NET_CHECK_SIGNATURE (Vector
, NET_VECTOR_SIGNATURE
);
152 ASSERT (Vector
->RefCnt
> 0);
156 if (Vector
->RefCnt
> 0) {
160 if (Vector
->Free
!= NULL
) {
162 // Call external free function to free the vector if it
163 // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
164 // first block since it is allocated by us
166 if (Vector
->Flag
& NET_VECTOR_OWN_FIRST
) {
167 gBS
->FreePool (Vector
->Block
[0].Bulk
);
170 Vector
->Free (Vector
->Arg
);
174 // Free each memory block associated with the Vector
176 for (Index
= 0; Index
< Vector
->BlockNum
; Index
++) {
177 gBS
->FreePool (Vector
->Block
[Index
].Bulk
);
181 gBS
->FreePool (Vector
);
186 Free the buffer and its associated NET_VECTOR.
188 @param[in] Nbuf Pointer to the NET_BUF to be freed.
197 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
198 ASSERT (Nbuf
->RefCnt
> 0);
202 if (Nbuf
->RefCnt
== 0) {
204 // Update Vector only when NBuf is to be released. That is,
205 // all the sharing of Nbuf increse Vector's RefCnt by one
207 NetbufFreeVector (Nbuf
->Vector
);
208 gBS
->FreePool (Nbuf
);
214 Create a copy of NET_BUF that share the associated NET_DATA.
216 @param[in] Nbuf Pointer to the net buffer to be cloned.
218 @return Pointer to the cloned net buffer.If NULL, the
219 allocation failed due to resource limit.
230 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
232 Clone
= AllocatePool (NET_BUF_SIZE (Nbuf
->BlockOpNum
));
238 Clone
->Signature
= NET_BUF_SIGNATURE
;
240 InitializeListHead (&Clone
->List
);
242 Clone
->Ip
= Nbuf
->Ip
;
243 Clone
->Tcp
= Nbuf
->Tcp
;
245 CopyMem (Clone
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
247 NET_GET_REF (Nbuf
->Vector
);
249 Clone
->Vector
= Nbuf
->Vector
;
250 Clone
->BlockOpNum
= Nbuf
->BlockOpNum
;
251 Clone
->TotalSize
= Nbuf
->TotalSize
;
252 CopyMem (Clone
->BlockOp
, Nbuf
->BlockOp
, sizeof (NET_BLOCK_OP
) * Nbuf
->BlockOpNum
);
259 Create a duplicated copy of Nbuf, data is copied. Also leave some
260 head space before the data.
262 @param[in] Nbuf Pointer to the net buffer to be cloned.
263 @param[in, out] Duplicate Pointer to the net buffer to duplicate to, if NULL
264 a new net buffer is allocated.
265 @param[in] HeadSpace Length of the head space to reserve.
267 @return Pointer to the duplicated net buffer.If NULL, the
268 allocation failed due to resource limit.
275 IN OUT NET_BUF
*Duplicate OPTIONAL
,
281 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
283 if (Duplicate
== NULL
) {
284 Duplicate
= NetbufAlloc (Nbuf
->TotalSize
+ HeadSpace
);
287 if (Duplicate
== NULL
) {
292 // Don't set the IP and TCP head point, since it is most
293 // like that they are pointing to the memory of Nbuf.
295 CopyMem (Duplicate
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
296 NetbufReserve (Duplicate
, HeadSpace
);
298 Dst
= NetbufAllocSpace (Duplicate
, Nbuf
->TotalSize
, NET_BUF_TAIL
);
299 NetbufCopy (Nbuf
, 0, Nbuf
->TotalSize
, Dst
);
306 Free a list of net buffers.
308 @param[in, out] Head Pointer to the head of linked net buffers.
314 IN OUT LIST_ENTRY
*Head
321 Entry
= Head
->ForwardLink
;
323 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
324 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
325 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
327 RemoveEntryList (Entry
);
331 ASSERT (IsListEmpty (Head
));
336 Get the position of some byte in the net buffer. This can be used
337 to, for example, retrieve the IP header in the packet. It also
338 returns the fragment that contains the byte which is used mainly by
339 the buffer implementation itself.
341 @param[in] Nbuf Pointer to the net buffer.
342 @param[in] Offset The index or offset of the byte.
343 @param[out] Index Index of the fragment that contains the block.
345 @return * Pointer to the nth byte of data in the net buffer.
346 If NULL, there is no such data in the net buffer.
354 OUT UINT32
*Index OPTIONAL
357 NET_BLOCK_OP
*BlockOp
;
361 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
363 if (Offset
>= Nbuf
->TotalSize
) {
367 BlockOp
= Nbuf
->BlockOp
;
370 for (Loop
= 0; Loop
< Nbuf
->BlockOpNum
; Loop
++) {
372 if (Len
+ BlockOp
[Loop
].Size
<= Offset
) {
373 Len
+= BlockOp
[Loop
].Size
;
381 return BlockOp
[Loop
].Head
+ (Offset
- Len
);
390 Set the NET_BLOCK and corresponding NET_BLOCK_OP in
391 the buffer. All the pointers in NET_BLOCK and NET_BLOCK_OP
392 are set to the bulk's head and tail respectively. So, this
393 function alone can't be used by NetbufAlloc.
395 @param[in, out] Nbuf Pointer to the net buffer.
396 @param[in] Bulk Pointer to the data.
397 @param[in] Len Length of the bulk data.
398 @param[in] Index The data block index in the net buffer the bulk
399 data should belong to.
404 IN OUT NET_BUF
*Nbuf
,
410 NET_BLOCK_OP
*BlockOp
;
413 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
414 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
415 ASSERT (Index
< Nbuf
->BlockOpNum
);
417 Block
= &(Nbuf
->Vector
->Block
[Index
]);
418 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
421 BlockOp
->BlockHead
= Bulk
;
422 BlockOp
->BlockTail
= Bulk
+ Len
;
423 BlockOp
->Head
= Bulk
;
424 BlockOp
->Tail
= Bulk
+ Len
;
431 Set the NET_BLOCK_OP in the buffer. The corresponding NET_BLOCK
432 structure is left untouched. Some times, there is no 1:1 relationship
433 between NET_BLOCK and NET_BLOCK_OP. For example, that in NetbufGetFragment.
435 @param[in, out] Nbuf Pointer to the net buffer.
436 @param[in] Bulk Pointer to the data.
437 @param[in] Len Length of the bulk data.
438 @param[in] Index The data block index in the net buffer the bulk
439 data should belong to.
444 IN OUT NET_BUF
*Nbuf
,
450 NET_BLOCK_OP
*BlockOp
;
452 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
453 ASSERT (Index
< Nbuf
->BlockOpNum
);
455 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
456 BlockOp
->BlockHead
= Bulk
;
457 BlockOp
->BlockTail
= Bulk
+ Len
;
458 BlockOp
->Head
= Bulk
;
459 BlockOp
->Tail
= Bulk
+ Len
;
465 Helper function for NetbufClone. It is necessary because NetbufGetFragment
466 may allocate the first block to accomodate the HeadSpace and HeadLen. So, it
467 need to create a new NET_VECTOR. But, we want to avoid data copy by sharing
470 @param[in] Arg Point to the old NET_VECTOR.
474 NetbufGetFragmentFree (
480 Vector
= (NET_VECTOR
*)Arg
;
481 NetbufFreeVector (Vector
);
487 Create a NET_BUF structure which contains Len byte data of
488 Nbuf starting from Offset. A new NET_BUF structure will be
489 created but the associated data in NET_VECTOR is shared.
490 This function exists to do IP packet fragmentation.
492 @param[in] Nbuf Pointer to the net buffer to be cloned.
493 @param[in] Offset Starting point of the data to be included in new
495 @param[in] Len How many data to include in new data.
496 @param[in] HeadSpace How many bytes of head space to reserve for
499 @return Pointer to the cloned net buffer.If NULL, the
500 allocation failed due to resource limit.
514 NET_BLOCK_OP
*BlockOp
;
526 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
528 if ((Len
== 0) || (Offset
+ Len
> Nbuf
->TotalSize
)) {
533 // First find the first and last BlockOp that contains
534 // the valid data, and compute the offset of the first
535 // BlockOp and length of the last BlockOp
537 BlockOp
= Nbuf
->BlockOp
;
540 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
541 if (Offset
< Cur
+ BlockOp
[Index
].Size
) {
545 Cur
+= BlockOp
[Index
].Size
;
549 // First is the index of the first BlockOp, FirstSkip is
550 // the offset of the first byte in the first BlockOp.
553 FirstSkip
= Offset
- Cur
;
554 FirstLen
= BlockOp
[Index
].Size
- FirstSkip
;
557 //redundant assignment to make compiler happy.
562 if (Len
> FirstLen
) {
563 Cur
+= BlockOp
[Index
].Size
;
566 for (; Index
< Nbuf
->BlockOpNum
; Index
++) {
567 if (Offset
+ Len
<= Cur
+ BlockOp
[Index
].Size
) {
569 LastLen
= Offset
+ Len
- Cur
;
573 Cur
+= BlockOp
[Index
].Size
;
582 BlockOpNum
= Last
- First
+ 1;
585 if (HeadSpace
!= 0) {
587 // Allocate an extra block to accomdate the head space.
591 Child
= NetbufAllocStruct (1, BlockOpNum
);
597 FirstBulk
= AllocatePool (HeadSpace
);
599 if (FirstBulk
== NULL
) {
603 Vector
= Child
->Vector
;
604 Vector
->Free
= NetbufGetFragmentFree
;
605 Vector
->Arg
= Nbuf
->Vector
;
606 Vector
->Flag
= NET_VECTOR_OWN_FIRST
;
607 Vector
->Len
= HeadSpace
;
610 //Reserve the head space in the first block
612 NetbufSetBlock (Child
, FirstBulk
, HeadSpace
, 0);
613 Child
->BlockOp
[0].Head
+= HeadSpace
;
614 Child
->BlockOp
[0].Size
= 0;
618 Child
= NetbufAllocStruct (0, BlockOpNum
);
624 Child
->Vector
= Nbuf
->Vector
;
627 NET_GET_REF (Nbuf
->Vector
);
628 Child
->TotalSize
= Len
;
631 // Set all the BlockOp up, the first and last one are special
632 // and need special process.
636 Nbuf
->BlockOp
[First
].Head
+ FirstSkip
,
641 for (Index
= First
+ 1; Index
<= Last
- 1 ; Index
++) {
659 CopyMem (Child
->ProtoData
, Nbuf
->ProtoData
, NET_PROTO_DATA
);
664 gBS
->FreePool (Child
);
671 Build a NET_BUF from external blocks.
673 @param[in] ExtFragment Pointer to the data block.
674 @param[in] ExtNum The number of the data block.
675 @param[in] HeadSpace The head space to be reserved.
676 @param[in] HeadLen The length of the protocol header, This function
677 will pull that number of data into a linear block.
678 @param[in] ExtFree Pointer to the caller provided free function.
679 @param[in] Arg The argument passed to ExtFree when ExtFree is
682 @return Pointer to the net buffer built from the data blocks.
683 If NULL, the allocation failed due to resource limit.
689 IN NET_FRAGMENT
*ExtFragment
,
693 IN NET_VECTOR_EXT_FREE ExtFree
,
694 IN VOID
*Arg OPTIONAL
699 NET_FRAGMENT SavedFragment
;
704 UINT32 FirstBlockLen
;
711 ASSERT ((ExtFragment
!= NULL
) && (ExtNum
> 0) && (ExtFree
!= NULL
));
713 SavedFragment
.Bulk
= NULL
;
714 SavedFragment
.Len
= 0;
726 // No need to consolidate the header if the first block is
727 // longer than the header length or there is only one block.
729 if ((ExtFragment
[0].Len
>= HeadLen
) || (ExtNum
== 1)) {
734 // Allocate an extra block if we need to:
735 // 1. Allocate some header space
736 // 2. aggreate the packet header
738 if ((HeadSpace
!= 0) || (HeadLen
!= 0)) {
739 FirstBlockLen
= HeadLen
+ HeadSpace
;
740 FirstBlock
= AllocatePool (FirstBlockLen
);
742 if (FirstBlock
== NULL
) {
750 // Copy the header to the first block, reduce the NET_BLOCK
751 // to allocate by one for each block that is completely covered
752 // by the first bulk.
756 Header
= FirstBlock
+ HeadSpace
;
758 for (Index
= 0; Index
< ExtNum
; Index
++) {
759 if (Len
>= ExtFragment
[Index
].Len
) {
760 CopyMem (Header
, ExtFragment
[Index
].Bulk
, ExtFragment
[Index
].Len
);
762 Copied
+= ExtFragment
[Index
].Len
;
763 Len
-= ExtFragment
[Index
].Len
;
764 Header
+= ExtFragment
[Index
].Len
;
765 TotalLen
+= ExtFragment
[Index
].Len
;
770 // Increament the index number to point to the next
771 // non-empty fragment.
778 CopyMem (Header
, ExtFragment
[Index
].Bulk
, Len
);
784 // Adjust the block structure to exclude the data copied,
785 // So, the left-over block can be processed as other blocks.
786 // But it must be recovered later. (SavedIndex > 0) always
787 // holds since we don't aggreate the header if the first block
788 // is bigger enough that the header is continuous
791 SavedFragment
= ExtFragment
[Index
];
792 ExtFragment
[Index
].Bulk
+= Len
;
793 ExtFragment
[Index
].Len
-= Len
;
799 Nbuf
= NetbufAllocStruct (BlockNum
, BlockNum
);
805 Vector
= Nbuf
->Vector
;
806 Vector
->Free
= ExtFree
;
808 Vector
->Flag
= ((FirstBlockLen
!= 0) ? NET_VECTOR_OWN_FIRST
: 0);
811 // Set the first block up which may contain
812 // some head space and aggregated header
816 if (FirstBlockLen
!= 0) {
817 NetbufSetBlock (Nbuf
, FirstBlock
, HeadSpace
+ Copied
, 0);
818 Nbuf
->BlockOp
[0].Head
+= HeadSpace
;
819 Nbuf
->BlockOp
[0].Size
= Copied
;
824 for (; Index
< ExtNum
; Index
++) {
825 NetbufSetBlock (Nbuf
, ExtFragment
[Index
].Bulk
, ExtFragment
[Index
].Len
, CurBlock
);
826 TotalLen
+= ExtFragment
[Index
].Len
;
830 Vector
->Len
= TotalLen
+ HeadSpace
;
831 Nbuf
->TotalSize
= TotalLen
;
833 if (SavedIndex
!= 0) {
834 ExtFragment
[SavedIndex
] = SavedFragment
;
840 gBS
->FreePool (FirstBlock
);
846 Build a fragment table to contain the fragments in the
847 buffer. This is the opposite of the NetbufFromExt.
849 @param[in] Nbuf Point to the net buffer.
850 @param[in, out] ExtFragment Pointer to the data block.
851 @param[in, out] ExtNum The number of the data block.
853 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than ExtNum.
854 @retval EFI_SUCCESS Fragment table built.
861 IN OUT NET_FRAGMENT
*ExtFragment
,
862 IN OUT UINT32
*ExtNum
870 for (Index
= 0; (Index
< Nbuf
->BlockOpNum
); Index
++) {
871 if (Nbuf
->BlockOp
[Index
].Size
== 0) {
875 if (Current
< *ExtNum
) {
876 ExtFragment
[Current
].Bulk
= Nbuf
->BlockOp
[Index
].Head
;
877 ExtFragment
[Current
].Len
= Nbuf
->BlockOp
[Index
].Size
;
880 return EFI_BUFFER_TOO_SMALL
;
890 Build a NET_BUF from a list of NET_BUF.
892 @param[in] BufList A List of NET_BUF.
893 @param[in] HeadSpace The head space to be reserved.
894 @param[in] HeaderLen The length of the protocol header, This function
895 will pull that number of data into a linear block.
896 @param[in] ExtFree Pointer to the caller provided free function.
897 @param[in] Arg The argument passed to ExtFree when ExtFree is
900 @return Pointer to the net buffer built from the data
907 IN LIST_ENTRY
*BufList
,
910 IN NET_VECTOR_EXT_FREE ExtFree
,
911 IN VOID
*Arg OPTIONAL
914 NET_FRAGMENT
*Fragment
;
922 //Compute how many blocks are there
926 NET_LIST_FOR_EACH (Entry
, BufList
) {
927 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
928 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
929 FragmentNum
+= Nbuf
->BlockOpNum
;
933 //Allocate and copy block points
935 Fragment
= AllocatePool (sizeof (NET_FRAGMENT
) * FragmentNum
);
937 if (Fragment
== NULL
) {
943 NET_LIST_FOR_EACH (Entry
, BufList
) {
944 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
945 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
947 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
948 if (Nbuf
->BlockOp
[Index
].Size
) {
949 Fragment
[Current
].Bulk
= Nbuf
->BlockOp
[Index
].Head
;
950 Fragment
[Current
].Len
= Nbuf
->BlockOp
[Index
].Size
;
956 Nbuf
= NetbufFromExt (Fragment
, Current
, HeadSpace
, HeaderLen
, ExtFree
, Arg
);
957 gBS
->FreePool (Fragment
);
964 Reserve some space in the header room of the buffer.
965 Upon allocation, all the space are in the tail room
966 of the buffer. Call this function to move some space
967 to the header room. This function is quite limited in
968 that it can only reserver space from the first block
969 of an empty NET_BUF not built from the external. But
970 it should be enough for the network stack.
972 @param[in, out] Nbuf Pointer to the net buffer.
973 @param[in] Len The length of buffer to be reserverd.
979 IN OUT NET_BUF
*Nbuf
,
983 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
984 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
986 ASSERT ((Nbuf
->BlockOpNum
== 1) && (Nbuf
->TotalSize
== 0));
987 ASSERT ((Nbuf
->Vector
->Free
== NULL
) && (Nbuf
->Vector
->Len
>= Len
));
989 Nbuf
->BlockOp
[0].Head
+= Len
;
990 Nbuf
->BlockOp
[0].Tail
+= Len
;
992 ASSERT (Nbuf
->BlockOp
[0].Tail
<= Nbuf
->BlockOp
[0].BlockTail
);
997 Allocate some space from the header or tail of the buffer.
999 @param[in, out] Nbuf Pointer to the net buffer.
1000 @param[in] Len The length of the buffer to be allocated.
1001 @param [in] FromHead The flag to indicate whether reserve the data from
1002 head or tail. TRUE for from head, and FALSE for
1005 @return Pointer to the first byte of the allocated buffer.
1011 IN OUT NET_BUF
*Nbuf
,
1016 NET_BLOCK_OP
*BlockOp
;
1020 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1021 NET_CHECK_SIGNATURE (Nbuf
->Vector
, NET_VECTOR_SIGNATURE
);
1027 // Allocate some space from head. If the buffer is empty,
1028 // allocate from the first block. If it isn't, allocate
1029 // from the first non-empty block, or the block before that.
1031 if (Nbuf
->TotalSize
== 0) {
1034 NetbufGetByte (Nbuf
, 0, &Index
);
1036 if ((NET_HEADSPACE(&(Nbuf
->BlockOp
[Index
])) < Len
) && (Index
> 0)) {
1041 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
1043 if (NET_HEADSPACE (BlockOp
) < Len
) {
1047 BlockOp
->Head
-= Len
;
1048 BlockOp
->Size
+= Len
;
1049 Nbuf
->TotalSize
+= Len
;
1051 return BlockOp
->Head
;
1055 // Allocate some space from the tail. If the buffer is empty,
1056 // allocate from the first block. If it isn't, allocate
1057 // from the last non-empty block, or the block after that.
1059 if (Nbuf
->TotalSize
== 0) {
1062 NetbufGetByte (Nbuf
, Nbuf
->TotalSize
- 1, &Index
);
1064 if ((NET_TAILSPACE(&(Nbuf
->BlockOp
[Index
])) < Len
) &&
1065 (Index
< Nbuf
->BlockOpNum
- 1)) {
1071 BlockOp
= &(Nbuf
->BlockOp
[Index
]);
1073 if (NET_TAILSPACE (BlockOp
) < Len
) {
1077 SavedTail
= BlockOp
->Tail
;
1079 BlockOp
->Tail
+= Len
;
1080 BlockOp
->Size
+= Len
;
1081 Nbuf
->TotalSize
+= Len
;
1089 Trim a single NET_BLOCK.
1091 @param[in, out] BlockOp Pointer to the NET_BLOCK.
1092 @param[in] Len The length of the data to be trimmed.
1093 @param[in] FromHead The flag to indicate whether trim data from head or
1094 tail. TRUE for from head, and FALSE for from tail.
1099 IN OUT NET_BLOCK_OP
*BlockOp
,
1104 ASSERT (BlockOp
&& (BlockOp
->Size
>= Len
));
1106 BlockOp
->Size
-= Len
;
1109 BlockOp
->Head
+= Len
;
1111 BlockOp
->Tail
-= Len
;
1117 Trim some data from the header or tail of the buffer.
1119 @param[in, out] Nbuf Pointer to the net buffer.
1120 @param[in] Len The length of the data to be trimmed.
1121 @param[in] FromHead The flag to indicate whether trim data from head or
1122 tail. TRUE for from head, and FALSE for from tail.
1124 @return Length of the actually trimmed data.
1130 IN OUT NET_BUF
*Nbuf
,
1135 NET_BLOCK_OP
*BlockOp
;
1139 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1141 if (Len
> Nbuf
->TotalSize
) {
1142 Len
= Nbuf
->TotalSize
;
1146 // If FromTail is true, iterate backward. That
1147 // is, init Index to NBuf->BlockNum - 1, and
1148 // decrease it by 1 during each loop. Otherwise,
1149 // iterate forward. That is, init Index to 0, and
1150 // increase it by 1 during each loop.
1153 Nbuf
->TotalSize
-= Len
;
1155 Index
= (FromHead
? 0 : Nbuf
->BlockOpNum
- 1);
1156 BlockOp
= Nbuf
->BlockOp
;
1159 if (BlockOp
[Index
].Size
== 0) {
1160 Index
+= (FromHead
? 1 : -1);
1164 if (Len
> BlockOp
[Index
].Size
) {
1165 Len
-= BlockOp
[Index
].Size
;
1166 Trimmed
+= BlockOp
[Index
].Size
;
1167 NetblockTrim (&BlockOp
[Index
], BlockOp
[Index
].Size
, FromHead
);
1170 NetblockTrim (&BlockOp
[Index
], Len
, FromHead
);
1174 Index
+= (FromHead
? 1 : -1);
1182 Copy the data from the specific offset to the destination.
1184 @param[in] Nbuf Pointer to the net buffer.
1185 @param[in] Offset The sequence number of the first byte to copy.
1186 @param[in] Len Length of the data to copy.
1187 @param[in] Dest The destination of the data to copy to.
1189 @retval UINTN The length of the copied data.
1201 NET_BLOCK_OP
*BlockOp
;
1208 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1211 if ((Len
== 0) || (Nbuf
->TotalSize
<= Offset
)) {
1215 if (Nbuf
->TotalSize
- Offset
< Len
) {
1216 Len
= Nbuf
->TotalSize
- Offset
;
1219 BlockOp
= Nbuf
->BlockOp
;
1222 // Skip to the offset. Don't make "Offset-By-One" error here.
1223 // Cur + BLOCK.SIZE is the first sequence number of next block.
1224 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
1225 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
1226 // first byte is the next block's first byte.
1230 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
1231 if (BlockOp
[Index
].Size
== 0) {
1235 if (Offset
< Cur
+ BlockOp
[Index
].Size
) {
1239 Cur
+= BlockOp
[Index
].Size
;
1243 // Cur is the sequence number of the first byte in the block
1244 // Offset - Cur is the number of bytes before first byte to
1245 // to copy in the current block.
1247 Skip
= Offset
- Cur
;
1248 Left
= BlockOp
[Index
].Size
- Skip
;
1251 CopyMem (Dest
, BlockOp
[Index
].Head
+ Skip
, Len
);
1255 CopyMem (Dest
, BlockOp
[Index
].Head
+ Skip
, Left
);
1263 for (; Index
< Nbuf
->BlockOpNum
; Index
++) {
1264 if (Len
> BlockOp
[Index
].Size
) {
1265 Len
-= BlockOp
[Index
].Size
;
1266 Copied
+= BlockOp
[Index
].Size
;
1268 CopyMem (Dest
, BlockOp
[Index
].Head
, BlockOp
[Index
].Size
);
1269 Dest
+= BlockOp
[Index
].Size
;
1272 CopyMem (Dest
, BlockOp
[Index
].Head
, Len
);
1282 Initiate the net buffer queue.
1284 @param[in, out] NbufQue Pointer to the net buffer queue to be initiated.
1290 IN OUT NET_BUF_QUEUE
*NbufQue
1293 NbufQue
->Signature
= NET_QUE_SIGNATURE
;
1294 NbufQue
->RefCnt
= 1;
1295 InitializeListHead (&NbufQue
->List
);
1297 InitializeListHead (&NbufQue
->BufList
);
1298 NbufQue
->BufSize
= 0;
1299 NbufQue
->BufNum
= 0;
1304 Allocate an initialized net buffer queue.
1306 @return Pointer to the allocated net buffer queue.If NULL, the
1307 allocation failed due to resource limit.
1316 NET_BUF_QUEUE
*NbufQue
;
1318 NbufQue
= AllocatePool (sizeof (NET_BUF_QUEUE
));
1319 if (NbufQue
== NULL
) {
1323 NetbufQueInit (NbufQue
);
1330 Free a net buffer queue.
1332 @param[in] NbufQue Poitner to the net buffer queue to be freed.
1338 IN NET_BUF_QUEUE
*NbufQue
1341 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1345 if (NbufQue
->RefCnt
== 0) {
1346 NetbufQueFlush (NbufQue
);
1347 gBS
->FreePool (NbufQue
);
1353 Append a buffer to the end of the queue.
1355 @param[in, out] NbufQue Pointer to the net buffer queue.
1356 @param[in, out] Nbuf Pointer to the net buffer to be appended.
1362 IN OUT NET_BUF_QUEUE
*NbufQue
,
1363 IN OUT NET_BUF
*Nbuf
1366 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1367 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1369 InsertTailList (&NbufQue
->BufList
, &Nbuf
->List
);
1371 NbufQue
->BufSize
+= Nbuf
->TotalSize
;
1377 Remove a net buffer from head in the specific queue.
1379 @param[in, out] NbufQue Pointer to the net buffer queue.
1381 @return Pointer to the net buffer removed from the specific
1382 queue. If NULL, there is no net buffer in the specific
1389 IN OUT NET_BUF_QUEUE
*NbufQue
1394 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1396 if (NbufQue
->BufNum
== 0) {
1400 First
= NET_LIST_USER_STRUCT (NbufQue
->BufList
.ForwardLink
, NET_BUF
, List
);
1402 NetListRemoveHead (&NbufQue
->BufList
);
1404 NbufQue
->BufSize
-= First
->TotalSize
;
1411 Copy some data from the buffer queue to the destination.
1413 @param[in] NbufQue Pointer to the net buffer queue.
1414 @param[in] Offset The sequence number of the first byte to copy.
1415 @param[in] Len Length of the data to copy.
1416 @param[out] Dest The destination of the data to copy to.
1418 @return The length of the copied data. If 0, then the length is zero or offset
1419 suppress the total size of net buffer.
1425 IN NET_BUF_QUEUE
*NbufQue
,
1438 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1439 ASSERT (Dest
!= NULL
);
1441 if ((Len
== 0) || (NbufQue
->BufSize
<= Offset
)) {
1445 if (NbufQue
->BufSize
- Offset
< Len
) {
1446 Len
= NbufQue
->BufSize
- Offset
;
1450 // skip to the Offset
1455 NET_LIST_FOR_EACH (Entry
, &NbufQue
->BufList
) {
1456 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1458 if (Offset
< Cur
+ Nbuf
->TotalSize
) {
1462 Cur
+= Nbuf
->TotalSize
;
1466 // Copy the data in the first buffer.
1468 Skip
= Offset
- Cur
;
1469 Left
= Nbuf
->TotalSize
- Skip
;
1472 return NetbufCopy (Nbuf
, Skip
, Len
, Dest
);
1475 NetbufCopy (Nbuf
, Skip
, Left
, Dest
);
1481 // Iterate over the others
1483 Entry
= Entry
->ForwardLink
;
1485 while ((Len
> 0) && (Entry
!= &NbufQue
->BufList
)) {
1486 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1488 if (Len
> Nbuf
->TotalSize
) {
1489 Len
-= Nbuf
->TotalSize
;
1490 Copied
+= Nbuf
->TotalSize
;
1492 NetbufCopy (Nbuf
, 0, Nbuf
->TotalSize
, Dest
);
1493 Dest
+= Nbuf
->TotalSize
;
1496 NetbufCopy (Nbuf
, 0, Len
, Dest
);
1501 Entry
= Entry
->ForwardLink
;
1509 Trim some data from the queue header, release the buffer if
1510 whole buffer is trimmed.
1512 @param[in, out] NbufQue Pointer to the net buffer queue.
1513 @param[in] Len Length of the data to trim.
1515 @return The length of the data trimmed, or 0 if length of the data to trim is zero.
1521 IN OUT NET_BUF_QUEUE
*NbufQue
,
1530 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1536 if (Len
> NbufQue
->BufSize
) {
1537 Len
= NbufQue
->BufSize
;
1540 NbufQue
->BufSize
-= Len
;
1543 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &NbufQue
->BufList
) {
1544 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1546 if (Len
>= Nbuf
->TotalSize
) {
1547 Trimmed
+= Nbuf
->TotalSize
;
1548 Len
-= Nbuf
->TotalSize
;
1550 RemoveEntryList (Entry
);
1560 Trimmed
+= NetbufTrim (Nbuf
, Len
, NET_BUF_HEAD
);
1570 Flush the net buffer queue.
1572 @param[in, out] NbufQue Pointer to the queue to be flushed.
1578 IN OUT NET_BUF_QUEUE
*NbufQue
1581 NET_CHECK_SIGNATURE (NbufQue
, NET_QUE_SIGNATURE
);
1583 NetbufFreeList (&NbufQue
->BufList
);
1585 NbufQue
->BufNum
= 0;
1586 NbufQue
->BufSize
= 0;
1591 Compute checksum for a bulk of data.
1593 @param[in] Bulk Pointer to the data.
1594 @param[in] Len Length of the data, in bytes.
1596 @return The computed checksum.
1606 register UINT32 Sum
;
1611 Sum
+= *(UINT16
*) Bulk
;
1617 // Add left-over byte, if any
1620 Sum
+= *(UINT8
*) Bulk
;
1624 // Fold 32-bit sum to 16 bits
1626 while ((Sum
>> 16) != 0) {
1627 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
1631 return (UINT16
) Sum
;
1638 @param[in] Checksum1 The first checksum to be added.
1639 @param[in] Checksum2 The second checksum to be added.
1641 @return The new checksum.
1647 IN UINT16 Checksum1
,
1653 Sum
= Checksum1
+ Checksum2
;
1656 // two UINT16 can only add up to a carry of 1.
1658 if ((Sum
>> 16) != 0) {
1659 Sum
= (Sum
& 0xffff) + 1;
1663 return (UINT16
) Sum
;
1668 Compute the checksum for a NET_BUF.
1670 @param[in] Nbuf Pointer to the net buffer.
1672 @return The computed checksum.
1681 NET_BLOCK_OP
*BlockOp
;
1687 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1691 BlockOp
= Nbuf
->BlockOp
;
1693 for (Index
= 0; Index
< Nbuf
->BlockOpNum
; Index
++) {
1694 if (BlockOp
[Index
].Size
== 0) {
1698 BlockSum
= NetblockChecksum (BlockOp
[Index
].Head
, BlockOp
[Index
].Size
);
1700 if ((Offset
& 0x01) != 0) {
1702 // The checksum starts with an odd byte, swap
1703 // the checksum before added to total checksum
1705 BlockSum
= (UINT16
) NET_SWAP_SHORT (BlockSum
);
1708 TotalSum
= NetAddChecksum (BlockSum
, TotalSum
);
1709 Offset
+= BlockOp
[Index
].Size
;
1717 Compute the checksum for TCP/UDP pseudo header.
1718 Src, Dst are in network byte order. and Len is
1721 @param[in] Src The source address of the packet.
1722 @param[in] Dst The destination address of the packet.
1723 @param[in] Proto The protocol type of the packet.
1724 @param[in] Len The length of the packet.
1726 @return The computed checksum.
1731 NetPseudoHeadChecksum (
1741 // Zero the memory to relieve align problems
1743 ZeroMem (&Hdr
, sizeof (Hdr
));
1747 Hdr
.Protocol
= Proto
;
1748 Hdr
.Len
= HTONS (Len
);
1750 return NetblockChecksum ((UINT8
*) &Hdr
, sizeof (Hdr
));