netbuffer.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,942 行 · 第 1/3 页

C
1,942
字号
/*++

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 "NetBuffer.h"

STATIC
NET_BUF *
NetbufAllocStruct (
  IN UINT32                 BlockNum,
  IN UINT32                 BlockOpNum
  )
/*++

Routine Description:

  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.

Arguments:

  BlockNum   - The number of NET_BLOCK in the Vector of net buffer
  BlockOpNum - The number of NET_BLOCK_OP in the net buffer
Returns:

  NET_BUF * - Pointer to the allocated NET_BUF. If NULL 
              the allocation failed due to resource limit.

--*/  
{
  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;
}

NET_BUF  *
NetbufAlloc (
  IN UINT32                 Len
  )
/*++

Routine Description:

  Allocate a single block NET_BUF. Upon allocation, all the
  free space is in the tail room.

Arguments:

  Len - The length of the block.

Returns:

  NET_BUF * - Pointer to the allocated NET_BUF. If NULL 
              the allocation failed due to resource limit.

--*/
{
  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;
}

STATIC
VOID 
NetbufFreeVector (
  IN NET_VECTOR             *Vector
  )
/*++

Routine Description:

  Free the vector

Arguments:

  Vector  - Pointer to the NET_VECTOR to be freed.

Returns:

  None.

--*/

{
  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);
}

VOID
NetbufFree (
  IN NET_BUF                *Nbuf
  )
/*++

Routine Description:

  Free the buffer and its associated NET_VECTOR.

Arguments:

  Nbuf  - Pointer to the NET_BUF to be freed.

Returns:

  None.

--*/
{
  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);
  }
}

NET_BUF  *
NetbufClone (
  IN NET_BUF                *Nbuf
  )
/*++

Routine Description:

  Create a copy of NET_BUF that share the associated NET_DATA.

Arguments:

  Nbuf  - Pointer to the net buffer to be cloned.

Returns:

  NET_BUF *  - Pointer to the cloned net buffer.

--*/
{
  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;
}

NET_BUF  *
NetbufDuplicate (
  IN NET_BUF                *Nbuf,
  IN NET_BUF                *Duplicate        OPTIONAL,
  IN UINT32                 HeadSpace
  )
/*++

Routine Description:

  Create a duplicated copy of Nbuf, data is copied. Also leave some 
  head space before the data.

Arguments:

  Nbuf      - Pointer to the net buffer to be cloned.
  Duplicate - Pointer to the net buffer to duplicate to, if NULL a new net 
              buffer is allocated.
  HeadSpace - Length of the head space to reserve
  
Returns:

  NET_BUF *  - Pointer to the duplicated net buffer.

--*/
{
  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;
}

VOID
NetbufFreeList (
  IN NET_LIST_ENTRY         *Head
  )
/*++

Routine Description:

  Free a list of net buffers.

Arguments:

  Head  - Pointer to the head of linked net buffers.

Returns:

  None.

--*/
{
  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));
}

UINT8  *
NetbufGetByte (
  IN  NET_BUF               *Nbuf,
  IN  UINT32                Offset,
  OUT UINT32                *Index  OPTIONAL
  )
/*++

Routine Description:

  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.

Arguments:

  Nbuf   - Pointer to the net buffer.
  Offset - The index or offset of the byte
  Index  - Index of the fragment that contains the block
  
Returns:

  UINT8 *  - Pointer to the nth byte of data in the net buffer.
             If NULL, there is no such data in the net buffer.

--*/
{
  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;
}


STATIC
VOID
NetbufSetBlock (
  IN NET_BUF                *Nbuf,
  IN UINT8                  *Bulk,
  IN UINT32                 Len,
  IN UINT32                 Index
  )
/*++

Routine Description:

  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.

Arguments:

  Nbuf  - Pointer to the net buffer.
  Bulk  - Pointer to the data.
  Len   - Length of the bulk data.
  Index - The data block index in the net buffer the bulk data
          should belong to.

Returns:

  None.

--*/
{
  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;
}


STATIC
VOID
NetbufSetBlockOp (
  IN NET_BUF                *Nbuf,
  IN UINT8                  *Bulk,
  IN UINT32                 Len,
  IN UINT32                 Index
  )
/*++

Routine Description:

  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.

Arguments:

  Nbuf  - Pointer to the net buffer.
  Bulk  - Pointer to the data.
  Len   - Length of the bulk data.
  Index - The data block index in the net buffer the bulk data
          should belong to.

Returns:

  None.

--*/
{
  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;
}

STATIC 
VOID 
NetbufGetFragmentFree (
  IN VOID                   *Arg
  )
/*++

Routine Description:

  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.
  
Arguments:

  Arg       - Point to the old NET_VECTOR

Returns:

  NONE

--*/

{
  NET_VECTOR                *Vector;

  Vector = (NET_VECTOR *)Arg;
  NetbufFreeVector (Vector);
}


NET_BUF  *
NetbufGetFragment (
  IN NET_BUF                *Nbuf,
  IN UINT32                 Offset,
  IN UINT32                 Len,
  IN UINT32                 HeadSpace
  )
/*++

Routine Description:

  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.

Arguments:

  Nbuf      - Pointer to the net buffer to be cloned.
  Offset    - Starting point of the data to be included in new buffer.
  Len       - How many data to include in new data
  HeadSpace - How many bytes of head space to reserve for protocol header

Returns:

  NET_BUF *  - Pointer to the cloned net buffer.

--*/
{
  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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?