netbuffer.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,942 行 · 第 1/3 页
C
1,942 行
}
Cur += BlockOp[Index].Size;
}
} else {
Last = First;
LastLen = Len;
FirstLen = Len;
}
BlockOpNum = Last - First + 1;
CurBlockOp = 0;
if (HeadSpace != 0) {
//
// Allocate an extra block to accomdate the head space.
//
BlockOpNum++;
Child = NetbufAllocStruct (1, BlockOpNum);
if (Child == NULL) {
return NULL;
}
FirstBulk = NetAllocatePool (HeadSpace);
if (FirstBulk == NULL) {
goto FreeChild;
}
Vector = Child->Vector;
Vector->Free = NetbufGetFragmentFree;
Vector->Arg = Nbuf->Vector;
Vector->Flag = NET_VECTOR_OWN_FIRST;
Vector->Len = HeadSpace;
//
//Reserve the head space in the first block
//
NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);
Child->BlockOp[0].Head += HeadSpace;
Child->BlockOp[0].Size = 0;
CurBlockOp++;
}else {
Child = NetbufAllocStruct (0, BlockOpNum);
if (Child == NULL) {
return NULL;
}
Child->Vector = Nbuf->Vector;
}
NET_GET_REF (Nbuf->Vector);
Child->TotalSize = Len;
//
// Set all the BlockOp up, the first and last one are special
// and need special process.
//
NetbufSetBlockOp (
Child,
Nbuf->BlockOp[First].Head + FirstSkip,
FirstLen,
CurBlockOp++
);
for (Index = First + 1; Index <= Last - 1 ; Index++) {
NetbufSetBlockOp (
Child,
BlockOp[Index].Head,
BlockOp[Index].Size,
CurBlockOp++
);
}
if (First != Last) {
NetbufSetBlockOp (
Child,
BlockOp[Last].Head,
LastLen,
CurBlockOp
);
}
NetCopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
return Child;
FreeChild:
NetFreePool (Child);
return NULL;
}
NET_BUF *
NetbufFromExt (
IN NET_FRAGMENT *ExtFragment,
IN UINT32 ExtNum,
IN UINT32 HeadSpace,
IN UINT32 HeadLen,
IN NET_VECTOR_EXT_FREE ExtFree,
IN VOID *Arg OPTIONAL
)
/*++
Routine Description:
Build a NET_BUF from external blocks.
Arguments:
ExtFragment - Pointer to the data block.
ExtNum - The number of the data block.
HeadSpace - The head space to be reserved.
HeadLen - The length of the protocol header, This function
will pull that number of data into a linear block.
ExtFree - Pointer to the caller provided free function.
Arg - The argument passed to ExtFree when ExtFree
is called.
Returns:
NET_BUF * - Pointer to the net buffer built from the data blocks.
--*/
{
NET_BUF *Nbuf;
NET_VECTOR *Vector;
NET_FRAGMENT SavedFragment;
UINT32 SavedIndex;
UINT32 TotalLen;
UINT32 BlockNum;
UINT8 *FirstBlock;
UINT32 FirstBlockLen;
UINT8 *Header;
UINT32 CurBlock;
UINT32 Index;
UINT32 Len;
UINT32 Copied;
ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));
SavedFragment.Bulk = NULL;
SavedFragment.Len = 0;
FirstBlockLen = 0;
FirstBlock = NULL;
BlockNum = ExtNum;
Index = 0;
TotalLen = 0;
SavedIndex = 0;
Len = 0;
Copied = 0;
//
// No need to consolidate the header if the first block is
// longer than the header length or there is only one block.
//
if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {
HeadLen = 0;
}
//
// Allocate an extra block if we need to:
// 1. Allocate some header space
// 2. aggreate the packet header
//
if ((HeadSpace != 0) || (HeadLen != 0)) {
FirstBlockLen = HeadLen + HeadSpace;
FirstBlock = NetAllocatePool (FirstBlockLen);
if (FirstBlock == NULL) {
return NULL;
}
BlockNum++;
}
//
// Copy the header to the first block, reduce the NET_BLOCK
// to allocate by one for each block that is completely covered
// by the first bulk.
//
if (HeadLen != 0) {
Len = HeadLen;
Header = FirstBlock + HeadSpace;
for (Index = 0; Index < ExtNum; Index++) {
if (Len >= ExtFragment[Index].Len) {
NetCopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);
Copied += ExtFragment[Index].Len;
Len -= ExtFragment[Index].Len;
Header += ExtFragment[Index].Len;
TotalLen += ExtFragment[Index].Len;
BlockNum--;
if (Len == 0) {
//
// Increament the index number to point to the next
// non-empty fragment.
//
Index++;
break;
}
} else {
NetCopyMem (Header, ExtFragment[Index].Bulk, Len);
Copied += Len;
TotalLen += Len;
//
// Adjust the block structure to exclude the data copied,
// So, the left-over block can be processed as other blocks.
// But it must be recovered later. (SavedIndex > 0) always
// holds since we don't aggreate the header if the first block
// is bigger enough that the header is continuous
//
SavedIndex = Index;
SavedFragment = ExtFragment[Index];
ExtFragment[Index].Bulk += Len;
ExtFragment[Index].Len -= Len;
break;
}
}
}
Nbuf = NetbufAllocStruct (BlockNum, BlockNum);
if (Nbuf == NULL) {
goto FreeFirstBlock;
}
Vector = Nbuf->Vector;
Vector->Free = ExtFree;
Vector->Arg = Arg;
Vector->Flag = (FirstBlockLen ? NET_VECTOR_OWN_FIRST : 0);
//
// Set the first block up which may contain
// some head space and aggregated header
//
CurBlock = 0;
if (FirstBlockLen != 0) {
NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);
Nbuf->BlockOp[0].Head += HeadSpace;
Nbuf->BlockOp[0].Size = Copied;
CurBlock++;
}
for (; Index < ExtNum; Index++) {
NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);
TotalLen += ExtFragment[Index].Len;
CurBlock++;
}
Vector->Len = TotalLen + HeadSpace;
Nbuf->TotalSize = TotalLen;
if (SavedIndex) {
ExtFragment[SavedIndex] = SavedFragment;
}
return Nbuf;
FreeFirstBlock:
NetFreePool (FirstBlock);
return NULL;
}
EFI_STATUS
NetbufBuildExt (
IN NET_BUF *Nbuf,
IN NET_FRAGMENT *ExtFragment,
IN UINT32 *ExtNum
)
/*++
Routine Description:
Build a fragment table to contain the fragments in the
buffer. This is the opposite of the NetbufFromExt.
Arguments:
Nbuf - Point to the net buffer
ExtFragment - Pointer to the data block.
ExtNum - The number of the data block.
Returns:
EFI_BUFFER_TOO_SMALL - The number of non-empty block is bigger than ExtNum
EFI_SUCCESS - Fragment table built.
--*/
{
UINT32 Index;
UINT32 Current;
Current = 0;
for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {
if (Nbuf->BlockOp[Index].Size == 0) {
continue;
}
if (Current < *ExtNum) {
ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
ExtFragment[Current].Len = Nbuf->BlockOp[Index].Size;
Current++;
} else {
return EFI_BUFFER_TOO_SMALL;
}
}
*ExtNum = Current;
return EFI_SUCCESS;
}
NET_BUF *
NetbufFromBufList (
IN NET_LIST_ENTRY *BufList,
IN UINT32 HeadSpace,
IN UINT32 HeaderLen,
IN NET_VECTOR_EXT_FREE ExtFree,
IN VOID *Arg OPTIONAL
)
/*++
Routine Description:
Build a NET_BUF from a list of NET_BUF.
Arguments:
BufList - A List of NET_BUF.
HeadSpace - The head space to be reserved.
HeaderLen - The length of the protocol header, This function
will pull that number of data into a linear block.
ExtFree - Pointer to the caller provided free function.
Arg - The argument passed to ExtFree when ExtFree
is called.
Returns:
NET_BUF * - Pointer to the net buffer built from the data blocks.
--*/
{
NET_FRAGMENT *Fragment;
UINT32 FragmentNum;
NET_LIST_ENTRY *Entry;
NET_BUF *Nbuf;
UINT32 Index;
UINT32 Current;
//
//Compute how many blocks are there
//
FragmentNum = 0;
NET_LIST_FOR_EACH (Entry, BufList) {
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
FragmentNum += Nbuf->BlockOpNum;
}
//
//Allocate and copy block points
//
Fragment = NetAllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);
if (Fragment == NULL) {
return NULL;
}
Current = 0;
NET_LIST_FOR_EACH (Entry, BufList) {
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
if (Nbuf->BlockOp[Index].Size) {
Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
Fragment[Current].Len = Nbuf->BlockOp[Index].Size;
Current++;
}
}
}
Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);
NetFreePool (Fragment);
return Nbuf;
}
VOID
NetbufReserve (
IN NET_BUF *Nbuf,
IN UINT32 Len
)
/*++
Routine Description:
Reserve some space in the header room of the buffer.
Upon allocation, all the space are in the tail room
of the buffer. Call this function to move some space
to the header room. This function is quite limited in
that it can only reserver space from the first block
of an empty NET_BUF not built from the external. But
it should be enough for the network stack.
Arguments:
Nbuf - Pointer to the net buffer.
Len - The length of buffer to be reserverd.
Returns:
None.
--*/
{
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));
ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));
Nbuf->BlockOp[0].Head += Len;
Nbuf->BlockOp[0].Tail += Len;
ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);
}
UINT8 *
NetbufAllocSpace (
IN NET_BUF *Nbuf,
IN UINT32 Len,
IN BOOLEAN FromHead
)
/*++
Routine Description:
Allocate some space from the header or tail of the buffer.
Arguments:
Nbuf - Pointer to the net buffer.
Len - The length of the buffer to be allocated.
FromHead - The flag to indicate whether reserve the data
from head or tail. TRUE for from head, and
FALSE for from tail.
Returns:
UINT8 * - Pointer to the first byte of the allocated buffer.
--*/
{
NET_BLOCK_OP *BlockOp;
UINT32 Index;
UINT8 *SavedTail;
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
ASSERT (Len > 0);
if (FromHead) {
//
// Allocate some space from head. If the buffer is empty,
// allocate from the first block. If it isn't, allocate
// from the first non-empty block, or the block before that.
//
if (Nbuf->TotalSize == 0) {
Index = 0;
} else {
NetbufGetByte (Nbuf, 0, &Index);
if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
Index--;
}
}
BlockOp = &(Nbuf->BlockOp[Index]);
if (NET_HEADSPACE (BlockOp) < Len) {
return NULL;
}
BlockOp->Head -= Len;
BlockOp->Size += Len;
Nbuf->TotalSize += Len;
return BlockOp->Head;
} else {
//
// Allocate some space from the tail. If the buffer is empty,
// allocate from the first block. If it isn't, allocate
// from the last non-empty block, or the block after that.
//
if (Nbuf->TotalSize == 0) {
Index = 0;
} else {
NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
(Index < Nbuf->BlockOpNum - 1)) {
Index++;
}
}
BlockOp = &(Nbuf->BlockOp[Index]);
if (NET_TAILSPACE (BlockOp) < Len) {
return NULL;
}
SavedTail = BlockOp->Tail;
BlockOp->Tail += Len;
BlockOp->Size += Len;
Nbuf->TotalSize += Len;
return SavedTail;
}
}
STATIC
VOID
NetblockTrim (
IN NET_BLOCK_OP *BlockOp,
IN UINT32 Len,
IN BOOLEAN FromHead
)
/*++
Routine Description:
Trim a single NET_BLOCK.
Arguments:
BlockOp - Pointer to the NET_BLOCK.
Len - The length of the data to be trimmed.
FromHead - The flag to indicate whether trim data from
head or tail. TRUE for from head, and FALSE
for from tail.
Returns:
None.
--*/
{
ASSERT (BlockOp && (BlockOp->Size >= Len));
BlockOp->Size -= Len;
if (FromHead) {
BlockOp->Head += Len;
} else {
BlockOp->Tail -= Len;
}
}
UINT32
NetbufTrim (
IN NET_BUF *Nbuf,
IN UINT32 Len,
IN BOOLEAN FromHead
)
/*++
Routine Description:
Trim some data from the header or tail of the buffer.
Arguments:
Nbuf - Pointer to the net buffer.
Len - The length of the data to be trimmed.
FromHead - The flag to indicate whether trim data from
head or tail. TRUE for from head, and FALSE
for from tail.
Returns:
UINTN - Length of the actually trimmed data.
--*/
{
NET_BLOCK_OP *BlockOp;
UINT32 Index;
UINT32 Trimmed;
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
if (Len > Nbuf->TotalSize) {
Len = Nbuf->TotalSize;
}
//
// If FromTail is true, iterate backward. That
// is, init Index to NBuf->BlockNum - 1, and
// decrease it by 1 during each loop. Otherwise,
// iterate forward. That is, init Index to 0, and
// increase it by 1 during each loop.
//
Trimmed = 0;
Nbuf->TotalSize -= Len;
Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
BlockOp = Nbuf->BlockOp;
for (;;) {
if (BlockOp[Index].Size == 0) {
Index += (FromHead ? 1 : -1);
continue;
}
if (Len > BlockOp[Index].Size) {
Len -= BlockOp[Index].Size;
Trimmed += BlockOp[Index].Size;
NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
} else {
Trimmed += Len;
NetblockTrim (&BlockOp[Index], Len, FromHead);
break;
}
Index += (FromHead ? 1 : -1);
}
return Trimmed;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?