hikey: Add UEFI sources for reference

UEFI needs to be built outside Android build system.
Please follow the instructions in README.

The sources correspond to:
https://github.com/96boards/edk2/commit/14eae0c12e71fd33c4c0fc51e4475e8db02566cf
https://github.com/96boards/arm-trusted-firmware/commit/e9b4909dcd75fc4ae7041cfb83d28ab9adb7afdf
https://github.com/96boards/l-loader/commit/6b784ad5c4ab00e2b1c6f53cd5f74054e5d00a78
https://git.linaro.org/uefi/uefi-tools.git/commit/abe618f8ab72034fff1ce46c9c006a2c6bd40a7e

Change-Id: Ieeefdb63e673e0c8e64e0a1f02c7bddc63b2c7fb
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/uefi/linaro-edk2/MdeModulePkg/Library/DxeNetLib/NetBuffer.c b/uefi/linaro-edk2/MdeModulePkg/Library/DxeNetLib/NetBuffer.c
new file mode 100644
index 0000000..bbbdbc0
--- /dev/null
+++ b/uefi/linaro-edk2/MdeModulePkg/Library/DxeNetLib/NetBuffer.c
@@ -0,0 +1,1892 @@
+/** @file

+  Network library functions providing net buffer operation support.

+

+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>

+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.

+**/

+

+#include <Uefi.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. But all the NET_BLOCK_OP and

+  NET_BLOCK remain un-initialized.

+

+  @param[in]  BlockNum       The number of NET_BLOCK in the vector of net buffer

+  @param[in]  BlockOpNum     The number of NET_BLOCK_OP in the net buffer

+

+  @return                    Pointer to the allocated NET_BUF, or NULL if the

+                             allocation failed due to resource limit.

+

+**/

+NET_BUF *

+NetbufAllocStruct (

+  IN UINT32                 BlockNum,

+  IN UINT32                 BlockOpNum

+  )

+{

+  NET_BUF                   *Nbuf;

+  NET_VECTOR                *Vector;

+

+  ASSERT (BlockOpNum >= 1);

+

+  //

+  // Allocate three memory blocks.

+  //

+  Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));

+

+  if (Nbuf == NULL) {

+    return NULL;

+  }

+

+  Nbuf->Signature           = NET_BUF_SIGNATURE;

+  Nbuf->RefCnt              = 1;

+  Nbuf->BlockOpNum          = BlockOpNum;

+  InitializeListHead (&Nbuf->List);

+

+  if (BlockNum != 0) {

+    Vector = AllocateZeroPool (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:

+

+  FreePool (Nbuf);

+  return NULL;

+}

+

+

+/**

+  Allocate a single block NET_BUF. Upon allocation, all the

+  free space is in the tail room.

+

+  @param[in]  Len              The length of the block.

+

+  @return                      Pointer to the allocated NET_BUF, or NULL if the

+                               allocation failed due to resource limit.

+

+**/

+NET_BUF  *

+EFIAPI

+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 = AllocatePool (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:

+  FreePool (Nbuf);

+  return NULL;

+}

+

+/**

+  Free the net vector.

+

+  Decrease the reference count of the net vector by one. The real resource free

+  operation isn't performed until the reference count of the net vector is

+  decreased to 0.

+

+  @param[in]  Vector                Pointer to the NET_VECTOR to be freed.

+

+**/

+VOID

+NetbufFreeVector (

+  IN NET_VECTOR             *Vector

+  )

+{

+  UINT32                    Index;

+

+  ASSERT (Vector != NULL);

+  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) != 0) {

+      gBS->FreePool (Vector->Block[0].Bulk);

+    }

+

+    Vector->Free (Vector->Arg);

+

+  } else {

+    //

+    // Free each memory block associated with the Vector

+    //

+    for (Index = 0; Index < Vector->BlockNum; Index++) {

+      gBS->FreePool (Vector->Block[Index].Bulk);

+    }

+  }

+

+  FreePool (Vector);

+}

+

+

+/**

+  Free the net buffer and its associated NET_VECTOR.

+

+  Decrease the reference count of the net buffer by one. Free the associated net

+  vector and itself if the reference count of the net buffer is decreased to 0.

+  The net vector free operation just decrease the reference count of the net

+  vector by one and do the real resource free operation when the reference count

+  of the net vector is 0.

+

+  @param[in]  Nbuf                  Pointer to the NET_BUF to be freed.

+

+**/

+VOID

+EFIAPI

+NetbufFree (

+  IN NET_BUF                *Nbuf

+  )

+{

+  ASSERT (Nbuf != NULL);

+  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);

+    FreePool (Nbuf);

+  }

+}

+

+

+/**

+  Create a copy of the net buffer that shares the associated net vector.

+

+  The reference count of the newly created net buffer is set to 1. The reference

+  count of the associated net vector is increased by one.

+

+  @param[in]  Nbuf              Pointer to the net buffer to be cloned.

+

+  @return                       Pointer to the cloned net buffer, or NULL if the

+                                allocation failed due to resource limit.

+

+**/

+NET_BUF *

+EFIAPI

+NetbufClone (

+  IN NET_BUF                *Nbuf

+  )

+{

+  NET_BUF                   *Clone;

+

+  NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);

+

+  Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));

+

+  if (Clone == NULL) {

+    return NULL;

+  }

+

+  Clone->Signature  = NET_BUF_SIGNATURE;

+  Clone->RefCnt     = 1;

+  InitializeListHead (&Clone->List);

+

+  Clone->Ip   = Nbuf->Ip;

+  Clone->Tcp  = Nbuf->Tcp;

+

+  CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);

+

+  NET_GET_REF (Nbuf->Vector);

+

+  Clone->Vector     = Nbuf->Vector;

+  Clone->BlockOpNum = Nbuf->BlockOpNum;

+  Clone->TotalSize  = Nbuf->TotalSize;

+  CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);

+

+  return Clone;

+}

+

+

+/**

+  Create a duplicated copy of the net buffer with data copied and HeadSpace

+  bytes of head space reserved.

+

+  The duplicated net buffer will allocate its own memory to hold the data of the

+  source net buffer.

+

+  @param[in]       Nbuf         Pointer to the net buffer to be duplicated from.

+  @param[in, out]  Duplicate    Pointer to the net buffer to duplicate to, if

+                                NULL a new net buffer is allocated.

+  @param[in]      HeadSpace     Length of the head space to reserve.

+

+  @return                       Pointer to the duplicated net buffer, or NULL if

+                                the allocation failed due to resource limit.

+

+**/

+NET_BUF  *

+EFIAPI

+NetbufDuplicate (

+  IN NET_BUF                *Nbuf,

+  IN OUT 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.

+  //

+  CopyMem (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[in, out]  Head              Pointer to the head of linked net buffers.

+

+**/

+VOID

+EFIAPI

+NetbufFreeList (

+  IN OUT LIST_ENTRY         *Head

+  )

+{

+  LIST_ENTRY                *Entry;

+  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);

+

+    RemoveEntryList (Entry);

+    NetbufFree (Nbuf);

+  }

+

+  ASSERT (IsListEmpty (Head));

+}

+

+

+/**

+  Get the index of NET_BLOCK_OP that contains the byte at Offset in the net

+  buffer.

+

+  This can be used to, for example, retrieve the IP header in the packet. It

+  also can be used to get the fragment that contains the byte which is used

+  mainly by the library implementation itself.

+

+  @param[in]   Nbuf      Pointer to the net buffer.

+  @param[in]   Offset    The offset of the byte.

+  @param[out]  Index     Index of the NET_BLOCK_OP that contains the byte at

+                         Offset.

+

+  @return       Pointer to the Offset'th byte of data in the net buffer, or NULL

+                if there is no such data in the net buffer.

+

+**/

+UINT8  *

+EFIAPI

+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 net buffer and

+  corresponding net vector according to the bulk pointer and bulk length.

+

+  All the pointers in the Index'th 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[in, out]  Nbuf       Pointer to the net buffer.

+  @param[in]       Bulk       Pointer to the data.

+  @param[in]       Len        Length of the bulk data.

+  @param[in]       Index      The data block index in the net buffer the bulk

+                              data should belong to.

+

+**/

+VOID

+NetbufSetBlock (

+  IN OUT 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 net 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[in, out]  Nbuf       Pointer to the net buffer.

+  @param[in]       Bulk       Pointer to the data.

+  @param[in]       Len        Length of the bulk data.

+  @param[in]       Index      The data block index in the net buffer the bulk

+                              data should belong to.

+

+**/

+VOID

+NetbufSetBlockOp (

+  IN OUT 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 NetbufGetFragment. NetbufGetFragment may allocate the

+  first block to reserve HeadSpace bytes header space. So it needs to create a

+  new net vector for the first block and can avoid copy for the remaining data

+  by sharing the old net vector.

+

+  @param[in]  Arg                   Point to the old NET_VECTOR.

+

+**/

+VOID

+EFIAPI

+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[in]  Nbuf         Pointer to the net buffer to be extracted.

+  @param[in]  Offset       Starting point of the data to be included in the new

+                           net buffer.

+  @param[in]  Len          Bytes of data to be included in the new net buffer.

+  @param[in]  HeadSpace    Bytes of head space to reserve for protocol header.

+

+  @return                  Pointer to the cloned net buffer, or NULL if the

+                           allocation failed due to resource limit.

+

+**/

+NET_BUF  *

+EFIAPI

+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;

+

+  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;

+  }

+

+  ASSERT (Last >= First);

+  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 = AllocatePool (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; Index++) {

+    NetbufSetBlockOp (

+      Child,

+      BlockOp[Index].Head,

+      BlockOp[Index].Size,

+      CurBlockOp++

+      );

+  }

+

+  if (First != Last) {

+    NetbufSetBlockOp (

+      Child,

+      BlockOp[Last].Head,

+      LastLen,

+      CurBlockOp

+      );

+  }

+

+  CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);

+  return Child;

+

+FreeChild:

+

+  FreePool (Child);

+  return NULL;

+}

+

+

+

+/**

+  Build a NET_BUF from external blocks.

+

+  A new NET_BUF structure will be created from external blocks. Additional block

+  of memory will be allocated to hold reserved HeadSpace bytes of header room

+  and existing HeadLen bytes of header but the external blocks are shared by the

+  net buffer to avoid data copying.

+

+  @param[in]  ExtFragment           Pointer to the data block.

+  @param[in]  ExtNum                The number of the data blocks.

+  @param[in]  HeadSpace             The head space to be reserved.

+  @param[in]  HeadLen               The length of the protocol header, This function

+                                    will pull that number of data into a linear block.

+  @param[in]  ExtFree               Pointer to the caller provided free function.

+  @param[in]  Arg                   The argument passed to ExtFree when ExtFree is

+                                    called.

+

+  @return                  Pointer to the net buffer built from the data blocks,

+                           or NULL if the allocation failed due to resource

+                           limit.

+

+**/

+NET_BUF  *

+EFIAPI

+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    = AllocatePool (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) {

+        CopyMem (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 {

+        CopyMem (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 != 0) ? 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 != 0) {

+    ExtFragment[SavedIndex] = SavedFragment;

+  }

+

+  return Nbuf;

+

+FreeFirstBlock:

+  if (FirstBlock != NULL) {

+    FreePool (FirstBlock);

+  }

+  return NULL;

+}

+

+

+/**

+  Build a fragment table to contain the fragments in the net buffer. This is the

+  opposite operation of the NetbufFromExt.

+

+  @param[in]       Nbuf                  Point to the net buffer.

+  @param[in, out]  ExtFragment           Pointer to the data block.

+  @param[in, out]  ExtNum                The number of the data blocks.

+

+  @retval EFI_BUFFER_TOO_SMALL  The number of non-empty block is bigger than

+                                ExtNum.

+  @retval EFI_SUCCESS           Fragment table is built successfully.

+

+**/

+EFI_STATUS

+EFIAPI

+NetbufBuildExt (

+  IN NET_BUF                *Nbuf,

+  IN OUT NET_FRAGMENT       *ExtFragment,

+  IN OUT 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 buffer from a list of net buffers.

+

+  All the fragments will be collected from the list of NEW_BUF and then a new

+  net buffer will be created through NetbufFromExt.

+

+  @param[in]   BufList    A List of the net buffer.

+  @param[in]   HeadSpace  The head space to be reserved.

+  @param[in]   HeaderLen  The length of the protocol header, This function

+                          will pull that number of data into a linear block.

+  @param[in]   ExtFree    Pointer to the caller provided free function.

+  @param[in]   Arg        The argument passed to ExtFree when ExtFree is called.

+

+  @return                 Pointer to the net buffer built from the list of net

+                          buffers.

+

+**/

+NET_BUF  *

+EFIAPI

+NetbufFromBufList (

+  IN LIST_ENTRY             *BufList,

+  IN UINT32                 HeadSpace,

+  IN UINT32                 HeaderLen,

+  IN NET_VECTOR_EXT_FREE    ExtFree,

+  IN VOID                   *Arg              OPTIONAL

+  )

+{

+  NET_FRAGMENT              *Fragment;

+  UINT32                    FragmentNum;

+  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 = AllocatePool (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 != 0) {

+        Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;

+        Fragment[Current].Len  = Nbuf->BlockOp[Index].Size;

+        Current++;

+      }

+    }

+  }

+

+  Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);

+  FreePool (Fragment);

+

+  return Nbuf;

+}

+

+

+/**

+  Reserve some space in the header room of the net 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 reserve 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[in, out]  Nbuf     Pointer to the net buffer.

+  @param[in]       Len      The length of buffer to be reserved from the header.

+

+**/

+VOID

+EFIAPI

+NetbufReserve (

+  IN OUT 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 Len bytes of space from the header or tail of the buffer.

+

+  @param[in, out]  Nbuf       Pointer to the net buffer.

+  @param[in]       Len        The length of the buffer to be allocated.

+  @param[in]       FromHead   The flag to indicate whether reserve the data

+                              from head (TRUE) or tail (FALSE).

+

+  @return                     Pointer to the first byte of the allocated buffer,

+                              or NULL if there is no sufficient space.

+

+**/

+UINT8*

+EFIAPI

+NetbufAllocSpace (

+  IN OUT NET_BUF            *Nbuf,

+  IN UINT32                 Len,

+  IN BOOLEAN                FromHead

+  )

+{

+  NET_BLOCK_OP              *BlockOp;

+  UINT32                    Index;

+  UINT8                     *SavedTail;

+

+  Index = 0;

+

+  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 by Len bytes from the header or tail.

+

+  @param[in, out]  BlockOp      Pointer to the NET_BLOCK.

+  @param[in]       Len          The length of the data to be trimmed.

+  @param[in]       FromHead     The flag to indicate whether trim data from head

+                                (TRUE) or tail (FALSE).

+

+**/

+VOID

+NetblockTrim (

+  IN OUT NET_BLOCK_OP       *BlockOp,

+  IN UINT32                 Len,

+  IN BOOLEAN                FromHead

+  )

+{

+  ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));

+

+  BlockOp->Size -= Len;

+

+  if (FromHead) {

+    BlockOp->Head += Len;

+  } else {

+    BlockOp->Tail -= Len;

+  }

+}

+

+

+/**

+  Trim Len bytes from the header or tail of the net buffer.

+

+  @param[in, out]  Nbuf         Pointer to the net buffer.

+  @param[in]       Len          The length of the data to be trimmed.

+  @param[in]      FromHead      The flag to indicate whether trim data from head

+                                (TRUE) or tail (FALSE).

+

+  @return    Length of the actually trimmed data, which is possible to be less

+             than Len because the TotalSize of Nbuf is less than Len.

+

+**/

+UINT32

+EFIAPI

+NetbufTrim (

+  IN OUT 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 Len bytes of data from the specific offset of the net buffer to the

+  destination memory.

+

+  The Len bytes of data may cross the several fragments of the net buffer.

+

+  @param[in]   Nbuf         Pointer to the net buffer.

+  @param[in]   Offset       The sequence number of the first byte to copy.

+  @param[in]   Len          Length of the data to copy.

+  @param[in]   Dest         The destination of the data to copy to.

+

+  @return           The length of the actual copied data, or 0 if the offset

+                    specified exceeds the total size of net buffer.

+

+**/

+UINT32

+EFIAPI

+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) {

+    CopyMem (Dest, BlockOp[Index].Head + Skip, Len);

+    return Len;

+  }

+

+  CopyMem (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;

+

+      CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);

+      Dest   += BlockOp[Index].Size;

+    } else {

+      Copied += Len;

+      CopyMem (Dest, BlockOp[Index].Head, Len);

+      break;

+    }

+  }

+

+  return Copied;

+}

+

+

+/**

+  Initiate the net buffer queue.

+

+  @param[in, out]  NbufQue   Pointer to the net buffer queue to be initialized.

+

+**/

+VOID

+EFIAPI

+NetbufQueInit (

+  IN OUT NET_BUF_QUEUE          *NbufQue

+  )

+{

+  NbufQue->Signature  = NET_QUE_SIGNATURE;

+  NbufQue->RefCnt     = 1;

+  InitializeListHead (&NbufQue->List);

+

+  InitializeListHead (&NbufQue->BufList);

+  NbufQue->BufSize  = 0;

+  NbufQue->BufNum   = 0;

+}

+

+

+/**

+  Allocate and initialize a net buffer queue.

+

+  @return         Pointer to the allocated net buffer queue, or NULL if the

+                  allocation failed due to resource limit.

+

+**/

+NET_BUF_QUEUE  *

+EFIAPI

+NetbufQueAlloc (

+  VOID

+  )

+{

+  NET_BUF_QUEUE             *NbufQue;

+

+  NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));

+  if (NbufQue == NULL) {

+    return NULL;

+  }

+

+  NetbufQueInit (NbufQue);

+

+  return NbufQue;

+}

+

+

+/**

+  Free a net buffer queue.

+

+  Decrease the reference count of the net buffer queue by one. The real resource

+  free operation isn't performed until the reference count of the net buffer

+  queue is decreased to 0.

+

+  @param[in]  NbufQue               Pointer to the net buffer queue to be freed.

+

+**/

+VOID

+EFIAPI

+NetbufQueFree (

+  IN NET_BUF_QUEUE          *NbufQue

+  )

+{

+  ASSERT (NbufQue != NULL);

+  NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);

+

+  NbufQue->RefCnt--;

+

+  if (NbufQue->RefCnt == 0) {

+    NetbufQueFlush (NbufQue);

+    FreePool (NbufQue);

+  }

+}

+

+

+/**

+  Append a net buffer to the net buffer queue.

+

+  @param[in, out]  NbufQue            Pointer to the net buffer queue.

+  @param[in, out]  Nbuf               Pointer to the net buffer to be appended.

+

+**/

+VOID

+EFIAPI

+NetbufQueAppend (

+  IN OUT NET_BUF_QUEUE          *NbufQue,

+  IN OUT NET_BUF                *Nbuf

+  )

+{

+  NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);

+  NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);

+

+  InsertTailList (&NbufQue->BufList, &Nbuf->List);

+

+  NbufQue->BufSize += Nbuf->TotalSize;

+  NbufQue->BufNum++;

+}

+

+

+/**

+  Remove a net buffer from the head in the specific queue and return it.

+

+  @param[in, out]  NbufQue               Pointer to the net buffer queue.

+

+  @return           Pointer to the net buffer removed from the specific queue,

+                    or NULL if there is no net buffer in the specific queue.

+

+**/

+NET_BUF  *

+EFIAPI

+NetbufQueRemove (

+  IN OUT 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 Len bytes of data from the net buffer queue at the specific offset to the

+  destination memory.

+

+  The copying operation is the same as NetbufCopy but applies to the net buffer

+  queue instead of the net buffer.

+

+  @param[in]   NbufQue         Pointer to the net buffer queue.

+  @param[in]   Offset          The sequence number of the first byte to copy.

+  @param[in]   Len             Length of the data to copy.

+  @param[out]  Dest            The destination of the data to copy to.

+

+  @return       The length of the actual copied data, or 0 if the offset

+                specified exceeds the total size of net buffer queue.

+

+**/

+UINT32

+EFIAPI

+NetbufQueCopy (

+  IN NET_BUF_QUEUE          *NbufQue,

+  IN UINT32                 Offset,

+  IN UINT32                 Len,

+  OUT UINT8                 *Dest

+  )

+{

+  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;

+  }

+

+  ASSERT (Nbuf != NULL);

+

+  //

+  // 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 Len bytes of data from the buffer queue and free any net buffer

+  that is completely trimmed.

+

+  The trimming operation is the same as NetbufTrim but applies to the net buffer

+  queue instead of the net buffer.

+

+  @param[in, out]  NbufQue               Pointer to the net buffer queue.

+  @param[in]       Len                   Length of the data to trim.

+

+  @return   The actual length of the data trimmed.

+

+**/

+UINT32

+EFIAPI

+NetbufQueTrim (

+  IN OUT NET_BUF_QUEUE      *NbufQue,

+  IN UINT32                 Len

+  )

+{

+  LIST_ENTRY                *Entry;

+  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;

+

+      RemoveEntryList (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[in, out]  NbufQue               Pointer to the queue to be flushed.

+

+**/

+VOID

+EFIAPI

+NetbufQueFlush (

+  IN OUT NET_BUF_QUEUE          *NbufQue

+  )

+{

+  NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);

+

+  NetbufFreeList (&NbufQue->BufList);

+

+  NbufQue->BufNum   = 0;

+  NbufQue->BufSize  = 0;

+}

+

+

+/**

+  Compute the checksum for a bulk of data.

+

+  @param[in]   Bulk                  Pointer to the data.

+  @param[in]   Len                   Length of the data, in bytes.

+

+  @return    The computed checksum.

+

+**/

+UINT16

+EFIAPI

+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) != 0) {

+    Sum = (Sum & 0xffff) + (Sum >> 16);

+

+  }

+

+  return (UINT16) Sum;

+}

+

+

+/**

+  Add two checksums.

+

+  @param[in]   Checksum1             The first checksum to be added.

+  @param[in]   Checksum2             The second checksum to be added.

+

+  @return         The new checksum.

+

+**/

+UINT16

+EFIAPI

+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) != 0) {

+    Sum = (Sum & 0xffff) + 1;

+

+  }

+

+  return (UINT16) Sum;

+}

+

+

+/**

+  Compute the checksum for a NET_BUF.

+

+  @param[in]   Nbuf                  Pointer to the net buffer.

+

+  @return    The computed checksum.

+

+**/

+UINT16

+EFIAPI

+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) != 0) {

+      //

+      // The checksum starts with an odd byte, swap

+      // the checksum before added to total checksum

+      //

+      BlockSum = SwapBytes16 (BlockSum);

+    }

+

+    TotalSum = NetAddChecksum (BlockSum, TotalSum);

+    Offset  += BlockOp[Index].Size;

+  }

+

+  return TotalSum;

+}

+

+

+/**

+  Compute the checksum for TCP/UDP pseudo header.

+

+  Src and Dst are in network byte order, and Len is in host byte order.

+

+  @param[in]   Src                   The source address of the packet.

+  @param[in]   Dst                   The destination address of the packet.

+  @param[in]   Proto                 The protocol type of the packet.

+  @param[in]   Len                   The length of the packet.

+

+  @return   The computed checksum.

+

+**/

+UINT16

+EFIAPI

+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

+  //

+  ZeroMem (&Hdr, sizeof (Hdr));

+

+  Hdr.SrcIp     = Src;

+  Hdr.DstIp     = Dst;

+  Hdr.Protocol  = Proto;

+  Hdr.Len       = HTONS (Len);

+

+  return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));

+}

+

+/**

+  Compute the checksum for TCP6/UDP6 pseudo header.

+

+  Src and Dst are in network byte order, and Len is in host byte order.

+

+  @param[in]   Src                   The source address of the packet.

+  @param[in]   Dst                   The destination address of the packet.

+  @param[in]   NextHeader            The protocol type of the packet.

+  @param[in]   Len                   The length of the packet.

+

+  @return   The computed checksum.

+

+**/

+UINT16

+EFIAPI

+NetIp6PseudoHeadChecksum (

+  IN EFI_IPv6_ADDRESS       *Src,

+  IN EFI_IPv6_ADDRESS       *Dst,

+  IN UINT8                  NextHeader,

+  IN UINT32                 Len

+  )

+{

+  NET_IP6_PSEUDO_HDR        Hdr;

+

+  //

+  // Zero the memory to relieve align problems

+  //

+  ZeroMem (&Hdr, sizeof (Hdr));

+

+  IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);

+  IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);

+

+  Hdr.NextHeader = NextHeader;

+  Hdr.Len        = HTONL (Len);

+

+  return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));

+}

+

+/**

+  The function frees the net buffer which allocated by the IP protocol. It releases 

+  only the net buffer and doesn't call the external free function. 

+

+  This function should be called after finishing the process of mIpSec->ProcessExt() 

+  for outbound traffic. The (EFI_IPSEC2_PROTOCOL)->ProcessExt() allocates a new 

+  buffer for the ESP, so there needs a function to free the old net buffer.

+

+  @param[in]  Nbuf       The network buffer to be freed.

+

+**/

+VOID

+NetIpSecNetbufFree (

+  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

+    //

+    NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);

+    ASSERT (Nbuf->Vector->RefCnt > 0);

+

+    Nbuf->Vector->RefCnt--;

+

+    if (Nbuf->Vector->RefCnt > 0) {

+      return;

+    }

+

+    //

+    // If NET_VECTOR_OWN_FIRST is set, release the first block since it is 

+    // allocated by us

+    //

+    if ((Nbuf->Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {

+      FreePool (Nbuf->Vector->Block[0].Bulk);

+    }

+    FreePool (Nbuf->Vector);

+    FreePool (Nbuf); 

+  } 

+}

+