mirror of https://github.com/acidanthera/audk.git
1760 lines
42 KiB
C
1760 lines
42 KiB
C
/** @file
|
|
|
|
Copyright (c) 2005 - 2006, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
NetBuffer.c
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
|
|
#include <Library/NetLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
|
|
/**
|
|
Allocate and build up the sketch for a NET_BUF. The net buffer allocated
|
|
has the BlockOpNum's NET_BLOCK_OP, and its associated NET_VECTOR has the
|
|
BlockNum's NET_BLOCK.
|
|
|
|
@param BlockNum The number of NET_BLOCK in the Vector of net buffer
|
|
@param BlockOpNum The number of NET_BLOCK_OP in the net buffer
|
|
|
|
@retval * Pointer to the allocated NET_BUF. If NULL the
|
|
allocation failed due to resource limit.
|
|
|
|
**/
|
|
STATIC
|
|
NET_BUF *
|
|
NetbufAllocStruct (
|
|
IN UINT32 BlockNum,
|
|
IN UINT32 BlockOpNum
|
|
)
|
|
{
|
|
NET_BUF *Nbuf;
|
|
NET_VECTOR *Vector;
|
|
|
|
ASSERT (BlockOpNum >= 1);
|
|
|
|
//
|
|
// Allocate three memory blocks.
|
|
//
|
|
Nbuf = NetAllocateZeroPool (NET_BUF_SIZE (BlockOpNum));
|
|
|
|
if (Nbuf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Nbuf->Signature = NET_BUF_SIGNATURE;
|
|
Nbuf->RefCnt = 1;
|
|
Nbuf->BlockOpNum = BlockOpNum;
|
|
NetListInit (&Nbuf->List);
|
|
|
|
if (BlockNum != 0) {
|
|
Vector = NetAllocateZeroPool (NET_VECTOR_SIZE (BlockNum));
|
|
|
|
if (Vector == NULL) {
|
|
goto FreeNbuf;
|
|
}
|
|
|
|
Vector->Signature = NET_VECTOR_SIGNATURE;
|
|
Vector->RefCnt = 1;
|
|
Vector->BlockNum = BlockNum;
|
|
Nbuf->Vector = Vector;
|
|
}
|
|
|
|
return Nbuf;
|
|
|
|
FreeNbuf:
|
|
|
|
NetFreePool (Nbuf);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Allocate a single block NET_BUF. Upon allocation, all the
|
|
free space is in the tail room.
|
|
|
|
@param Len The length of the block.
|
|
|
|
@retval * Pointer to the allocated NET_BUF. If NULL the
|
|
allocation failed due to resource limit.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufAlloc (
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
NET_BUF *Nbuf;
|
|
NET_VECTOR *Vector;
|
|
UINT8 *Bulk;
|
|
|
|
ASSERT (Len > 0);
|
|
|
|
Nbuf = NetbufAllocStruct (1, 1);
|
|
|
|
if (Nbuf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Bulk = NetAllocatePool (Len);
|
|
|
|
if (Bulk == NULL) {
|
|
goto FreeNBuf;
|
|
}
|
|
|
|
Vector = Nbuf->Vector;
|
|
Vector->Len = Len;
|
|
|
|
Vector->Block[0].Bulk = Bulk;
|
|
Vector->Block[0].Len = Len;
|
|
|
|
Nbuf->BlockOp[0].BlockHead = Bulk;
|
|
Nbuf->BlockOp[0].BlockTail = Bulk + Len;
|
|
|
|
Nbuf->BlockOp[0].Head = Bulk;
|
|
Nbuf->BlockOp[0].Tail = Bulk;
|
|
Nbuf->BlockOp[0].Size = 0;
|
|
|
|
return Nbuf;
|
|
|
|
FreeNBuf:
|
|
NetFreePool (Nbuf);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Free the vector
|
|
|
|
@param Vector Pointer to the NET_VECTOR to be freed.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
NetbufFreeVector (
|
|
IN NET_VECTOR *Vector
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE);
|
|
ASSERT (Vector->RefCnt > 0);
|
|
|
|
Vector->RefCnt--;
|
|
|
|
if (Vector->RefCnt > 0) {
|
|
return;
|
|
}
|
|
|
|
if (Vector->Free != NULL) {
|
|
//
|
|
// Call external free function to free the vector if it
|
|
// isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
|
|
// first block since it is allocated by us
|
|
//
|
|
if (Vector->Flag & NET_VECTOR_OWN_FIRST) {
|
|
NetFreePool (Vector->Block[0].Bulk);
|
|
}
|
|
|
|
Vector->Free (Vector->Arg);
|
|
|
|
} else {
|
|
//
|
|
// Free each memory block associated with the Vector
|
|
//
|
|
for (Index = 0; Index < Vector->BlockNum; Index++) {
|
|
NetFreePool (Vector->Block[Index].Bulk);
|
|
}
|
|
}
|
|
|
|
NetFreePool (Vector);
|
|
}
|
|
|
|
|
|
/**
|
|
Free the buffer and its associated NET_VECTOR.
|
|
|
|
@param Nbuf Pointer to the NET_BUF to be freed.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufFree (
|
|
IN NET_BUF *Nbuf
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
ASSERT (Nbuf->RefCnt > 0);
|
|
|
|
Nbuf->RefCnt--;
|
|
|
|
if (Nbuf->RefCnt == 0) {
|
|
//
|
|
// Update Vector only when NBuf is to be released. That is,
|
|
// all the sharing of Nbuf increse Vector's RefCnt by one
|
|
//
|
|
NetbufFreeVector (Nbuf->Vector);
|
|
NetFreePool (Nbuf);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Create a copy of NET_BUF that share the associated NET_DATA.
|
|
|
|
@param Nbuf Pointer to the net buffer to be cloned.
|
|
|
|
@retval * Pointer to the cloned net buffer.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufClone (
|
|
IN NET_BUF *Nbuf
|
|
)
|
|
{
|
|
NET_BUF *Clone;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
Clone = NetAllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));
|
|
|
|
if (Clone == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Clone->Signature = NET_BUF_SIGNATURE;
|
|
Clone->RefCnt = 1;
|
|
NetListInit (&Clone->List);
|
|
|
|
Clone->Ip = Nbuf->Ip;
|
|
Clone->Tcp = Nbuf->Tcp;
|
|
|
|
NetCopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
|
|
|
|
NET_GET_REF (Nbuf->Vector);
|
|
|
|
Clone->Vector = Nbuf->Vector;
|
|
Clone->BlockOpNum = Nbuf->BlockOpNum;
|
|
Clone->TotalSize = Nbuf->TotalSize;
|
|
NetCopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);
|
|
|
|
return Clone;
|
|
}
|
|
|
|
|
|
/**
|
|
Create a duplicated copy of Nbuf, data is copied. Also leave some
|
|
head space before the data.
|
|
|
|
@param Nbuf Pointer to the net buffer to be cloned.
|
|
@param Duplicate Pointer to the net buffer to duplicate to, if NULL
|
|
a new net buffer is allocated.
|
|
@param HeadSpace Length of the head space to reserve
|
|
|
|
@retval * Pointer to the duplicated net buffer.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufDuplicate (
|
|
IN NET_BUF *Nbuf,
|
|
IN NET_BUF *Duplicate OPTIONAL,
|
|
IN UINT32 HeadSpace
|
|
)
|
|
{
|
|
UINT8 *Dst;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
if (Duplicate == NULL) {
|
|
Duplicate = NetbufAlloc (Nbuf->TotalSize + HeadSpace);
|
|
}
|
|
|
|
if (Duplicate == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Don't set the IP and TCP head point, since it is most
|
|
// like that they are pointing to the memory of Nbuf.
|
|
//
|
|
NetCopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
|
|
NetbufReserve (Duplicate, HeadSpace);
|
|
|
|
Dst = NetbufAllocSpace (Duplicate, Nbuf->TotalSize, NET_BUF_TAIL);
|
|
NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dst);
|
|
|
|
return Duplicate;
|
|
}
|
|
|
|
|
|
/**
|
|
Free a list of net buffers.
|
|
|
|
@param Head Pointer to the head of linked net buffers.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufFreeList (
|
|
IN NET_LIST_ENTRY *Head
|
|
)
|
|
{
|
|
NET_LIST_ENTRY *Entry;
|
|
NET_LIST_ENTRY *Next;
|
|
NET_BUF *Nbuf;
|
|
|
|
Entry = Head->ForwardLink;
|
|
|
|
NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
|
|
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
NetListRemoveEntry (Entry);
|
|
NetbufFree (Nbuf);
|
|
}
|
|
|
|
ASSERT (NetListIsEmpty (Head));
|
|
}
|
|
|
|
|
|
/**
|
|
Get the position of some byte in the net buffer. This can be used
|
|
to, for example, retrieve the IP header in the packet. It also
|
|
returns the fragment that contains the byte which is used mainly by
|
|
the buffer implementation itself.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Offset The index or offset of the byte
|
|
@param Index Index of the fragment that contains the block
|
|
|
|
@retval * Pointer to the nth byte of data in the net buffer.
|
|
If NULL, there is no such data in the net buffer.
|
|
|
|
**/
|
|
UINT8 *
|
|
NetbufGetByte (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Offset,
|
|
OUT UINT32 *Index OPTIONAL
|
|
)
|
|
{
|
|
NET_BLOCK_OP *BlockOp;
|
|
UINT32 Loop;
|
|
UINT32 Len;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
if (Offset >= Nbuf->TotalSize) {
|
|
return NULL;
|
|
}
|
|
|
|
BlockOp = Nbuf->BlockOp;
|
|
Len = 0;
|
|
|
|
for (Loop = 0; Loop < Nbuf->BlockOpNum; Loop++) {
|
|
|
|
if (Len + BlockOp[Loop].Size <= Offset) {
|
|
Len += BlockOp[Loop].Size;
|
|
continue;
|
|
}
|
|
|
|
if (Index != NULL) {
|
|
*Index = Loop;
|
|
}
|
|
|
|
return BlockOp[Loop].Head + (Offset - Len);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Set the NET_BLOCK and corresponding NET_BLOCK_OP in
|
|
the buffer. All the pointers in NET_BLOCK and NET_BLOCK_OP
|
|
are set to the bulk's head and tail respectively. So, this
|
|
function alone can't be used by NetbufAlloc.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Bulk Pointer to the data.
|
|
@param Len Length of the bulk data.
|
|
@param Index The data block index in the net buffer the bulk
|
|
data should belong to.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
NetbufSetBlock (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT8 *Bulk,
|
|
IN UINT32 Len,
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
NET_BLOCK_OP *BlockOp;
|
|
NET_BLOCK *Block;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
|
|
ASSERT (Index < Nbuf->BlockOpNum);
|
|
|
|
Block = &(Nbuf->Vector->Block[Index]);
|
|
BlockOp = &(Nbuf->BlockOp[Index]);
|
|
Block->Len = Len;
|
|
Block->Bulk = Bulk;
|
|
BlockOp->BlockHead = Bulk;
|
|
BlockOp->BlockTail = Bulk + Len;
|
|
BlockOp->Head = Bulk;
|
|
BlockOp->Tail = Bulk + Len;
|
|
BlockOp->Size = Len;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Set the NET_BLOCK_OP in the buffer. The corresponding NET_BLOCK
|
|
structure is left untouched. Some times, there is no 1:1 relationship
|
|
between NET_BLOCK and NET_BLOCK_OP. For example, that in NetbufGetFragment.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Bulk Pointer to the data.
|
|
@param Len Length of the bulk data.
|
|
@param Index The data block index in the net buffer the bulk
|
|
data should belong to.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
NetbufSetBlockOp (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT8 *Bulk,
|
|
IN UINT32 Len,
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
NET_BLOCK_OP *BlockOp;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
ASSERT (Index < Nbuf->BlockOpNum);
|
|
|
|
BlockOp = &(Nbuf->BlockOp[Index]);
|
|
BlockOp->BlockHead = Bulk;
|
|
BlockOp->BlockTail = Bulk + Len;
|
|
BlockOp->Head = Bulk;
|
|
BlockOp->Tail = Bulk + Len;
|
|
BlockOp->Size = Len;
|
|
}
|
|
|
|
|
|
/**
|
|
Helper function for NetbufClone. It is necessary because NetbufGetFragment
|
|
may allocate the first block to accomodate the HeadSpace and HeadLen. So, it
|
|
need to create a new NET_VECTOR. But, we want to avoid data copy by sharing
|
|
the old NET_VECTOR.
|
|
|
|
@param Arg Point to the old NET_VECTOR
|
|
|
|
@return NONE
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
NetbufGetFragmentFree (
|
|
IN VOID *Arg
|
|
)
|
|
{
|
|
NET_VECTOR *Vector;
|
|
|
|
Vector = (NET_VECTOR *)Arg;
|
|
NetbufFreeVector (Vector);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Create a NET_BUF structure which contains Len byte data of
|
|
Nbuf starting from Offset. A new NET_BUF structure will be
|
|
created but the associated data in NET_VECTOR is shared.
|
|
This function exists to do IP packet fragmentation.
|
|
|
|
@param Nbuf Pointer to the net buffer to be cloned.
|
|
@param Offset Starting point of the data to be included in new
|
|
buffer.
|
|
@param Len How many data to include in new data
|
|
@param HeadSpace How many bytes of head space to reserve for
|
|
protocol header
|
|
|
|
@retval * Pointer to the cloned net buffer.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufGetFragment (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Offset,
|
|
IN UINT32 Len,
|
|
IN UINT32 HeadSpace
|
|
)
|
|
{
|
|
NET_BUF *Child;
|
|
NET_VECTOR *Vector;
|
|
NET_BLOCK_OP *BlockOp;
|
|
UINT32 CurBlockOp;
|
|
UINT32 BlockOpNum;
|
|
UINT8 *FirstBulk;
|
|
UINT32 Index;
|
|
UINT32 First;
|
|
UINT32 Last;
|
|
UINT32 FirstSkip;
|
|
UINT32 FirstLen;
|
|
UINT32 LastLen;
|
|
UINT32 Cur;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// First find the first and last BlockOp that contains
|
|
// the valid data, and compute the offset of the first
|
|
// BlockOp and length of the last BlockOp
|
|
//
|
|
BlockOp = Nbuf->BlockOp;
|
|
Cur = 0;
|
|
|
|
for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
|
|
if (Offset < Cur + BlockOp[Index].Size) {
|
|
break;
|
|
}
|
|
|
|
Cur += BlockOp[Index].Size;
|
|
}
|
|
|
|
//
|
|
// First is the index of the first BlockOp, FirstSkip is
|
|
// the offset of the first byte in the first BlockOp.
|
|
//
|
|
First = Index;
|
|
FirstSkip = Offset - Cur;
|
|
FirstLen = BlockOp[Index].Size - FirstSkip;
|
|
|
|
//
|
|
//redundant assignment to make compiler happy.
|
|
//
|
|
Last = 0;
|
|
LastLen = 0;
|
|
|
|
if (Len > FirstLen) {
|
|
Cur += BlockOp[Index].Size;
|
|
Index++;
|
|
|
|
for (; Index < Nbuf->BlockOpNum; Index++) {
|
|
if (Offset + Len <= Cur + BlockOp[Index].Size) {
|
|
Last = Index;
|
|
LastLen = Offset + Len - Cur;
|
|
break;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Build a NET_BUF from external blocks.
|
|
|
|
@param ExtFragment Pointer to the data block.
|
|
@param ExtNum The number of the data block.
|
|
@param HeadSpace The head space to be reserved.
|
|
@param HeadLen The length of the protocol header, This function
|
|
will pull that number of data into a linear block.
|
|
@param ExtFree Pointer to the caller provided free function.
|
|
@param Arg The argument passed to ExtFree when ExtFree is
|
|
called.
|
|
|
|
@retval * Pointer to the net buffer built from the data
|
|
blocks.
|
|
|
|
**/
|
|
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
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
Build a fragment table to contain the fragments in the
|
|
buffer. This is the opposite of the NetbufFromExt.
|
|
|
|
@param Nbuf Point to the net buffer
|
|
@param ExtFragment Pointer to the data block.
|
|
@param ExtNum The number of the data block.
|
|
|
|
@retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than ExtNum
|
|
@retval EFI_SUCCESS Fragment table built.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
NetbufBuildExt (
|
|
IN NET_BUF *Nbuf,
|
|
IN NET_FRAGMENT *ExtFragment,
|
|
IN UINT32 *ExtNum
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
Build a NET_BUF from a list of NET_BUF.
|
|
|
|
@param BufList A List of NET_BUF.
|
|
@param HeadSpace The head space to be reserved.
|
|
@param HeaderLen The length of the protocol header, This function
|
|
will pull that number of data into a linear block.
|
|
@param ExtFree Pointer to the caller provided free function.
|
|
@param Arg The argument passed to ExtFree when ExtFree is
|
|
called.
|
|
|
|
@retval * Pointer to the net buffer built from the data
|
|
blocks.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufFromBufList (
|
|
IN NET_LIST_ENTRY *BufList,
|
|
IN UINT32 HeadSpace,
|
|
IN UINT32 HeaderLen,
|
|
IN NET_VECTOR_EXT_FREE ExtFree,
|
|
IN VOID *Arg OPTIONAL
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
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.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Len The length of buffer to be reserverd.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufReserve (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
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);
|
|
}
|
|
|
|
|
|
/**
|
|
Allocate some space from the header or tail of the buffer.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Len The length of the buffer to be allocated.
|
|
@param FromHead The flag to indicate whether reserve the data from
|
|
head or tail. TRUE for from head, and FALSE for
|
|
from tail.
|
|
|
|
@retval * Pointer to the first byte of the allocated buffer.
|
|
|
|
**/
|
|
UINT8 *
|
|
NetbufAllocSpace (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Len,
|
|
IN BOOLEAN FromHead
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Trim a single NET_BLOCK.
|
|
|
|
@param BlockOp Pointer to the NET_BLOCK.
|
|
@param Len The length of the data to be trimmed.
|
|
@param FromHead The flag to indicate whether trim data from head or
|
|
tail. TRUE for from head, and FALSE for from tail.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
NetblockTrim (
|
|
IN NET_BLOCK_OP *BlockOp,
|
|
IN UINT32 Len,
|
|
IN BOOLEAN FromHead
|
|
)
|
|
{
|
|
ASSERT (BlockOp && (BlockOp->Size >= Len));
|
|
|
|
BlockOp->Size -= Len;
|
|
|
|
if (FromHead) {
|
|
BlockOp->Head += Len;
|
|
} else {
|
|
BlockOp->Tail -= Len;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Trim some data from the header or tail of the buffer.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Len The length of the data to be trimmed.
|
|
@param FromHead The flag to indicate whether trim data from head or
|
|
tail. TRUE for from head, and FALSE for from tail.
|
|
|
|
@retval UINTN Length of the actually trimmed data.
|
|
|
|
**/
|
|
UINT32
|
|
NetbufTrim (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Len,
|
|
IN BOOLEAN FromHead
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
Copy the data from the specific offset to the destination.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
@param Offset The sequence number of the first byte to copy.
|
|
@param Len Length of the data to copy.
|
|
@param Dest The destination of the data to copy to.
|
|
|
|
@retval UINTN The length of the copied data.
|
|
|
|
**/
|
|
UINT32
|
|
NetbufCopy (
|
|
IN NET_BUF *Nbuf,
|
|
IN UINT32 Offset,
|
|
IN UINT32 Len,
|
|
IN UINT8 *Dest
|
|
)
|
|
{
|
|
NET_BLOCK_OP *BlockOp;
|
|
UINT32 Skip;
|
|
UINT32 Left;
|
|
UINT32 Copied;
|
|
UINT32 Index;
|
|
UINT32 Cur;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
ASSERT (Dest);
|
|
|
|
if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
|
|
return 0;
|
|
}
|
|
|
|
if (Nbuf->TotalSize - Offset < Len) {
|
|
Len = Nbuf->TotalSize - Offset;
|
|
}
|
|
|
|
BlockOp = Nbuf->BlockOp;
|
|
|
|
//
|
|
// Skip to the offset. Don't make "Offset-By-One" error here.
|
|
// Cur + BLOCK.SIZE is the first sequence number of next block.
|
|
// So, (Offset < Cur + BLOCK.SIZE) means that the first byte
|
|
// is in the current block. if (Offset == Cur + BLOCK.SIZE), the
|
|
// first byte is the next block's first byte.
|
|
//
|
|
Cur = 0;
|
|
|
|
for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
|
|
if (BlockOp[Index].Size == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (Offset < Cur + BlockOp[Index].Size) {
|
|
break;
|
|
}
|
|
|
|
Cur += BlockOp[Index].Size;
|
|
}
|
|
|
|
//
|
|
// Cur is the sequence number of the first byte in the block
|
|
// Offset - Cur is the number of bytes before first byte to
|
|
// to copy in the current block.
|
|
//
|
|
Skip = Offset - Cur;
|
|
Left = BlockOp[Index].Size - Skip;
|
|
|
|
if (Len <= Left) {
|
|
NetCopyMem (Dest, BlockOp[Index].Head + Skip, Len);
|
|
return Len;
|
|
}
|
|
|
|
NetCopyMem (Dest, BlockOp[Index].Head + Skip, Left);
|
|
|
|
Dest += Left;
|
|
Len -= Left;
|
|
Copied = Left;
|
|
|
|
Index++;
|
|
|
|
for (; Index < Nbuf->BlockOpNum; Index++) {
|
|
if (Len > BlockOp[Index].Size) {
|
|
Len -= BlockOp[Index].Size;
|
|
Copied += BlockOp[Index].Size;
|
|
|
|
NetCopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
|
|
Dest += BlockOp[Index].Size;
|
|
} else {
|
|
Copied += Len;
|
|
NetCopyMem (Dest, BlockOp[Index].Head, Len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Copied;
|
|
}
|
|
|
|
|
|
/**
|
|
Initiate the net buffer queue.
|
|
|
|
@param NbufQue Pointer to the net buffer queue to be initiated.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufQueInit (
|
|
IN NET_BUF_QUEUE *NbufQue
|
|
)
|
|
{
|
|
NbufQue->Signature = NET_QUE_SIGNATURE;
|
|
NbufQue->RefCnt = 1;
|
|
NetListInit (&NbufQue->List);
|
|
|
|
NetListInit (&NbufQue->BufList);
|
|
NbufQue->BufSize = 0;
|
|
NbufQue->BufNum = 0;
|
|
}
|
|
|
|
|
|
/**
|
|
Allocate an initialized net buffer queue.
|
|
|
|
None.
|
|
|
|
@retval * Pointer to the allocated net buffer queue.
|
|
|
|
**/
|
|
NET_BUF_QUEUE *
|
|
NetbufQueAlloc (
|
|
VOID
|
|
)
|
|
{
|
|
NET_BUF_QUEUE *NbufQue;
|
|
|
|
NbufQue = NetAllocatePool (sizeof (NET_BUF_QUEUE));
|
|
if (NbufQue == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
NetbufQueInit (NbufQue);
|
|
|
|
return NbufQue;
|
|
}
|
|
|
|
|
|
/**
|
|
Free a net buffer queue.
|
|
|
|
@param NbufQue Poitner to the net buffer queue to be freed.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufQueFree (
|
|
IN NET_BUF_QUEUE *NbufQue
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
|
|
NbufQue->RefCnt--;
|
|
|
|
if (NbufQue->RefCnt == 0) {
|
|
NetbufQueFlush (NbufQue);
|
|
NetFreePool (NbufQue);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Append a buffer to the end of the queue.
|
|
|
|
@param NbufQue Pointer to the net buffer queue.
|
|
@param Nbuf Pointer to the net buffer to be appended.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufQueAppend (
|
|
IN NET_BUF_QUEUE *NbufQue,
|
|
IN NET_BUF *Nbuf
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
NetListInsertTail (&NbufQue->BufList, &Nbuf->List);
|
|
|
|
NbufQue->BufSize += Nbuf->TotalSize;
|
|
NbufQue->BufNum++;
|
|
}
|
|
|
|
|
|
/**
|
|
Remove a net buffer from head in the specific queue.
|
|
|
|
@param NbufQue Pointer to the net buffer queue.
|
|
|
|
@retval * Pointer to the net buffer removed from the specific
|
|
queue.
|
|
|
|
**/
|
|
NET_BUF *
|
|
NetbufQueRemove (
|
|
IN NET_BUF_QUEUE *NbufQue
|
|
)
|
|
{
|
|
NET_BUF *First;
|
|
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
|
|
if (NbufQue->BufNum == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
|
|
|
|
NetListRemoveHead (&NbufQue->BufList);
|
|
|
|
NbufQue->BufSize -= First->TotalSize;
|
|
NbufQue->BufNum--;
|
|
return First;
|
|
}
|
|
|
|
|
|
/**
|
|
Copy some data from the buffer queue to the destination.
|
|
|
|
@param NbufQue Pointer to the net buffer queue.
|
|
@param Offset The sequence number of the first byte to copy.
|
|
@param Len Length of the data to copy.
|
|
@param Dest The destination of the data to copy to.
|
|
|
|
@retval UINTN The length of the copied data.
|
|
|
|
**/
|
|
UINT32
|
|
NetbufQueCopy (
|
|
IN NET_BUF_QUEUE *NbufQue,
|
|
IN UINT32 Offset,
|
|
IN UINT32 Len,
|
|
IN UINT8 *Dest
|
|
)
|
|
{
|
|
NET_LIST_ENTRY *Entry;
|
|
NET_BUF *Nbuf;
|
|
UINT32 Skip;
|
|
UINT32 Left;
|
|
UINT32 Cur;
|
|
UINT32 Copied;
|
|
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
ASSERT (Dest != NULL);
|
|
|
|
if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
|
|
return 0;
|
|
}
|
|
|
|
if (NbufQue->BufSize - Offset < Len) {
|
|
Len = NbufQue->BufSize - Offset;
|
|
}
|
|
|
|
//
|
|
// skip to the Offset
|
|
//
|
|
Cur = 0;
|
|
Nbuf = NULL;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
|
|
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
|
|
|
|
if (Offset < Cur + Nbuf->TotalSize) {
|
|
break;
|
|
}
|
|
|
|
Cur += Nbuf->TotalSize;
|
|
}
|
|
|
|
//
|
|
// Copy the data in the first buffer.
|
|
//
|
|
Skip = Offset - Cur;
|
|
Left = Nbuf->TotalSize - Skip;
|
|
|
|
if (Len < Left) {
|
|
return NetbufCopy (Nbuf, Skip, Len, Dest);
|
|
}
|
|
|
|
NetbufCopy (Nbuf, Skip, Left, Dest);
|
|
Dest += Left;
|
|
Len -= Left;
|
|
Copied = Left;
|
|
|
|
//
|
|
// Iterate over the others
|
|
//
|
|
Entry = Entry->ForwardLink;
|
|
|
|
while ((Len > 0) && (Entry != &NbufQue->BufList)) {
|
|
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
|
|
|
|
if (Len > Nbuf->TotalSize) {
|
|
Len -= Nbuf->TotalSize;
|
|
Copied += Nbuf->TotalSize;
|
|
|
|
NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
|
|
Dest += Nbuf->TotalSize;
|
|
|
|
} else {
|
|
NetbufCopy (Nbuf, 0, Len, Dest);
|
|
Copied += Len;
|
|
break;
|
|
}
|
|
|
|
Entry = Entry->ForwardLink;
|
|
}
|
|
|
|
return Copied;
|
|
}
|
|
|
|
|
|
/**
|
|
Trim some data from the queue header, release the buffer if
|
|
whole buffer is trimmed.
|
|
|
|
@param NbufQue Pointer to the net buffer queue.
|
|
@param Len Length of the data to trim.
|
|
|
|
@retval UINTN The length of the data trimmed.
|
|
|
|
**/
|
|
UINT32
|
|
NetbufQueTrim (
|
|
IN NET_BUF_QUEUE *NbufQue,
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
NET_LIST_ENTRY *Entry;
|
|
NET_LIST_ENTRY *Next;
|
|
NET_BUF *Nbuf;
|
|
UINT32 Trimmed;
|
|
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
|
|
if (Len == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (Len > NbufQue->BufSize) {
|
|
Len = NbufQue->BufSize;
|
|
}
|
|
|
|
NbufQue->BufSize -= Len;
|
|
Trimmed = 0;
|
|
|
|
NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
|
|
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
|
|
|
|
if (Len >= Nbuf->TotalSize) {
|
|
Trimmed += Nbuf->TotalSize;
|
|
Len -= Nbuf->TotalSize;
|
|
|
|
NetListRemoveEntry (Entry);
|
|
NetbufFree (Nbuf);
|
|
|
|
NbufQue->BufNum--;
|
|
|
|
if (Len == 0) {
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Trimmed;
|
|
}
|
|
|
|
|
|
/**
|
|
Flush the net buffer queue.
|
|
|
|
@param NbufQue Pointer to the queue to be flushed.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
NetbufQueFlush (
|
|
IN NET_BUF_QUEUE *NbufQue
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
|
|
|
|
NetbufFreeList (&NbufQue->BufList);
|
|
|
|
NbufQue->BufNum = 0;
|
|
NbufQue->BufSize = 0;
|
|
}
|
|
|
|
|
|
/**
|
|
Compute checksum for a bulk of data.
|
|
|
|
@param Bulk Pointer to the data.
|
|
@param Len Length of the data, in bytes.
|
|
|
|
@retval UINT16 The computed checksum.
|
|
|
|
**/
|
|
UINT16
|
|
NetblockChecksum (
|
|
IN UINT8 *Bulk,
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
register UINT32 Sum;
|
|
|
|
Sum = 0;
|
|
|
|
while (Len > 1) {
|
|
Sum += *(UINT16 *) Bulk;
|
|
Bulk += 2;
|
|
Len -= 2;
|
|
}
|
|
|
|
//
|
|
// Add left-over byte, if any
|
|
//
|
|
if (Len > 0) {
|
|
Sum += *(UINT8 *) Bulk;
|
|
}
|
|
|
|
//
|
|
// Fold 32-bit sum to 16 bits
|
|
//
|
|
while (Sum >> 16) {
|
|
Sum = (Sum & 0xffff) + (Sum >> 16);
|
|
|
|
}
|
|
|
|
return (UINT16) Sum;
|
|
}
|
|
|
|
|
|
/**
|
|
Add two checksums.
|
|
|
|
@param Checksum1 The first checksum to be added.
|
|
@param Checksum2 The second checksum to be added.
|
|
|
|
@retval UINT16 The new checksum.
|
|
|
|
**/
|
|
UINT16
|
|
NetAddChecksum (
|
|
IN UINT16 Checksum1,
|
|
IN UINT16 Checksum2
|
|
)
|
|
{
|
|
UINT32 Sum;
|
|
|
|
Sum = Checksum1 + Checksum2;
|
|
|
|
//
|
|
// two UINT16 can only add up to a carry of 1.
|
|
//
|
|
if (Sum >> 16) {
|
|
Sum = (Sum & 0xffff) + 1;
|
|
|
|
}
|
|
|
|
return (UINT16) Sum;
|
|
}
|
|
|
|
|
|
/**
|
|
Compute the checksum for a NET_BUF.
|
|
|
|
@param Nbuf Pointer to the net buffer.
|
|
|
|
@retval UINT16 The computed checksum.
|
|
|
|
**/
|
|
UINT16
|
|
NetbufChecksum (
|
|
IN NET_BUF *Nbuf
|
|
)
|
|
{
|
|
NET_BLOCK_OP *BlockOp;
|
|
UINT32 Offset;
|
|
UINT16 TotalSum;
|
|
UINT16 BlockSum;
|
|
UINT32 Index;
|
|
|
|
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
|
|
|
|
TotalSum = 0;
|
|
Offset = 0;
|
|
BlockOp = Nbuf->BlockOp;
|
|
|
|
for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
|
|
if (BlockOp[Index].Size == 0) {
|
|
continue;
|
|
}
|
|
|
|
BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
|
|
|
|
if (Offset & 0x01) {
|
|
//
|
|
// The checksum starts with an odd byte, swap
|
|
// the checksum before added to total checksum
|
|
//
|
|
BlockSum = (UINT16) NET_SWAP_SHORT (BlockSum);
|
|
}
|
|
|
|
TotalSum = NetAddChecksum (BlockSum, TotalSum);
|
|
Offset += BlockOp[Index].Size;
|
|
}
|
|
|
|
return TotalSum;
|
|
}
|
|
|
|
|
|
/**
|
|
Compute the checksum for TCP/UDP pseudo header.
|
|
Src, Dst are in network byte order. and Len is
|
|
in host byte order.
|
|
|
|
@param Src The source address of the packet.
|
|
@param Dst The destination address of the packet.
|
|
@param Proto The protocol type of the packet.
|
|
@param Len The length of the packet.
|
|
|
|
@retval UINT16 The computed checksum.
|
|
|
|
**/
|
|
UINT16
|
|
NetPseudoHeadChecksum (
|
|
IN IP4_ADDR Src,
|
|
IN IP4_ADDR Dst,
|
|
IN UINT8 Proto,
|
|
IN UINT16 Len
|
|
)
|
|
{
|
|
NET_PSEUDO_HDR Hdr;
|
|
|
|
//
|
|
// Zero the memory to relieve align problems
|
|
//
|
|
NetZeroMem (&Hdr, sizeof (Hdr));
|
|
|
|
Hdr.SrcIp = Src;
|
|
Hdr.DstIp = Dst;
|
|
Hdr.Protocol = Proto;
|
|
Hdr.Len = HTONS (Len);
|
|
|
|
return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
|
|
}
|