Home | History | Annotate | Download | only in DxeNetLib
      1 /** @file
      2   Network library functions providing net buffer operation support.
      3 
      4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 **/
     13 
     14 #include <Uefi.h>
     15 
     16 #include <Library/NetLib.h>
     17 #include <Library/BaseLib.h>
     18 #include <Library/DebugLib.h>
     19 #include <Library/BaseMemoryLib.h>
     20 #include <Library/UefiBootServicesTableLib.h>
     21 #include <Library/MemoryAllocationLib.h>
     22 
     23 
     24 /**
     25   Allocate and build up the sketch for a NET_BUF.
     26 
     27   The net buffer allocated has the BlockOpNum's NET_BLOCK_OP, and its associated
     28   NET_VECTOR has the BlockNum's NET_BLOCK. But all the NET_BLOCK_OP and
     29   NET_BLOCK remain un-initialized.
     30 
     31   @param[in]  BlockNum       The number of NET_BLOCK in the vector of net buffer
     32   @param[in]  BlockOpNum     The number of NET_BLOCK_OP in the net buffer
     33 
     34   @return                    Pointer to the allocated NET_BUF, or NULL if the
     35                              allocation failed due to resource limit.
     36 
     37 **/
     38 NET_BUF *
     39 NetbufAllocStruct (
     40   IN UINT32                 BlockNum,
     41   IN UINT32                 BlockOpNum
     42   )
     43 {
     44   NET_BUF                   *Nbuf;
     45   NET_VECTOR                *Vector;
     46 
     47   ASSERT (BlockOpNum >= 1);
     48 
     49   //
     50   // Allocate three memory blocks.
     51   //
     52   Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));
     53 
     54   if (Nbuf == NULL) {
     55     return NULL;
     56   }
     57 
     58   Nbuf->Signature           = NET_BUF_SIGNATURE;
     59   Nbuf->RefCnt              = 1;
     60   Nbuf->BlockOpNum          = BlockOpNum;
     61   InitializeListHead (&Nbuf->List);
     62 
     63   if (BlockNum != 0) {
     64     Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum));
     65 
     66     if (Vector == NULL) {
     67       goto FreeNbuf;
     68     }
     69 
     70     Vector->Signature = NET_VECTOR_SIGNATURE;
     71     Vector->RefCnt    = 1;
     72     Vector->BlockNum  = BlockNum;
     73     Nbuf->Vector      = Vector;
     74   }
     75 
     76   return Nbuf;
     77 
     78 FreeNbuf:
     79 
     80   FreePool (Nbuf);
     81   return NULL;
     82 }
     83 
     84 
     85 /**
     86   Allocate a single block NET_BUF. Upon allocation, all the
     87   free space is in the tail room.
     88 
     89   @param[in]  Len              The length of the block.
     90 
     91   @return                      Pointer to the allocated NET_BUF, or NULL if the
     92                                allocation failed due to resource limit.
     93 
     94 **/
     95 NET_BUF  *
     96 EFIAPI
     97 NetbufAlloc (
     98   IN UINT32                 Len
     99   )
    100 {
    101   NET_BUF                   *Nbuf;
    102   NET_VECTOR                *Vector;
    103   UINT8                     *Bulk;
    104 
    105   ASSERT (Len > 0);
    106 
    107   Nbuf = NetbufAllocStruct (1, 1);
    108 
    109   if (Nbuf == NULL) {
    110     return NULL;
    111   }
    112 
    113   Bulk = AllocatePool (Len);
    114 
    115   if (Bulk == NULL) {
    116     goto FreeNBuf;
    117   }
    118 
    119   Vector = Nbuf->Vector;
    120   Vector->Len                 = Len;
    121 
    122   Vector->Block[0].Bulk       = Bulk;
    123   Vector->Block[0].Len        = Len;
    124 
    125   Nbuf->BlockOp[0].BlockHead  = Bulk;
    126   Nbuf->BlockOp[0].BlockTail  = Bulk + Len;
    127 
    128   Nbuf->BlockOp[0].Head       = Bulk;
    129   Nbuf->BlockOp[0].Tail       = Bulk;
    130   Nbuf->BlockOp[0].Size       = 0;
    131 
    132   return Nbuf;
    133 
    134 FreeNBuf:
    135   FreePool (Nbuf);
    136   return NULL;
    137 }
    138 
    139 /**
    140   Free the net vector.
    141 
    142   Decrease the reference count of the net vector by one. The real resource free
    143   operation isn't performed until the reference count of the net vector is
    144   decreased to 0.
    145 
    146   @param[in]  Vector                Pointer to the NET_VECTOR to be freed.
    147 
    148 **/
    149 VOID
    150 NetbufFreeVector (
    151   IN NET_VECTOR             *Vector
    152   )
    153 {
    154   UINT32                    Index;
    155 
    156   ASSERT (Vector != NULL);
    157   NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE);
    158   ASSERT (Vector->RefCnt > 0);
    159 
    160   Vector->RefCnt--;
    161 
    162   if (Vector->RefCnt > 0) {
    163     return;
    164   }
    165 
    166   if (Vector->Free != NULL) {
    167     //
    168     // Call external free function to free the vector if it
    169     // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
    170     // first block since it is allocated by us
    171     //
    172     if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {
    173       gBS->FreePool (Vector->Block[0].Bulk);
    174     }
    175 
    176     Vector->Free (Vector->Arg);
    177 
    178   } else {
    179     //
    180     // Free each memory block associated with the Vector
    181     //
    182     for (Index = 0; Index < Vector->BlockNum; Index++) {
    183       gBS->FreePool (Vector->Block[Index].Bulk);
    184     }
    185   }
    186 
    187   FreePool (Vector);
    188 }
    189 
    190 
    191 /**
    192   Free the net buffer and its associated NET_VECTOR.
    193 
    194   Decrease the reference count of the net buffer by one. Free the associated net
    195   vector and itself if the reference count of the net buffer is decreased to 0.
    196   The net vector free operation just decrease the reference count of the net
    197   vector by one and do the real resource free operation when the reference count
    198   of the net vector is 0.
    199 
    200   @param[in]  Nbuf                  Pointer to the NET_BUF to be freed.
    201 
    202 **/
    203 VOID
    204 EFIAPI
    205 NetbufFree (
    206   IN NET_BUF                *Nbuf
    207   )
    208 {
    209   ASSERT (Nbuf != NULL);
    210   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    211   ASSERT (Nbuf->RefCnt > 0);
    212 
    213   Nbuf->RefCnt--;
    214 
    215   if (Nbuf->RefCnt == 0) {
    216     //
    217     // Update Vector only when NBuf is to be released. That is,
    218     // all the sharing of Nbuf increse Vector's RefCnt by one
    219     //
    220     NetbufFreeVector (Nbuf->Vector);
    221     FreePool (Nbuf);
    222   }
    223 }
    224 
    225 
    226 /**
    227   Create a copy of the net buffer that shares the associated net vector.
    228 
    229   The reference count of the newly created net buffer is set to 1. The reference
    230   count of the associated net vector is increased by one.
    231 
    232   @param[in]  Nbuf              Pointer to the net buffer to be cloned.
    233 
    234   @return                       Pointer to the cloned net buffer, or NULL if the
    235                                 allocation failed due to resource limit.
    236 
    237 **/
    238 NET_BUF *
    239 EFIAPI
    240 NetbufClone (
    241   IN NET_BUF                *Nbuf
    242   )
    243 {
    244   NET_BUF                   *Clone;
    245 
    246   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    247 
    248   Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));
    249 
    250   if (Clone == NULL) {
    251     return NULL;
    252   }
    253 
    254   Clone->Signature  = NET_BUF_SIGNATURE;
    255   Clone->RefCnt     = 1;
    256   InitializeListHead (&Clone->List);
    257 
    258   Clone->Ip   = Nbuf->Ip;
    259   Clone->Tcp  = Nbuf->Tcp;
    260 
    261   CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
    262 
    263   NET_GET_REF (Nbuf->Vector);
    264 
    265   Clone->Vector     = Nbuf->Vector;
    266   Clone->BlockOpNum = Nbuf->BlockOpNum;
    267   Clone->TotalSize  = Nbuf->TotalSize;
    268   CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);
    269 
    270   return Clone;
    271 }
    272 
    273 
    274 /**
    275   Create a duplicated copy of the net buffer with data copied and HeadSpace
    276   bytes of head space reserved.
    277 
    278   The duplicated net buffer will allocate its own memory to hold the data of the
    279   source net buffer.
    280 
    281   @param[in]       Nbuf         Pointer to the net buffer to be duplicated from.
    282   @param[in, out]  Duplicate    Pointer to the net buffer to duplicate to, if
    283                                 NULL a new net buffer is allocated.
    284   @param[in]      HeadSpace     Length of the head space to reserve.
    285 
    286   @return                       Pointer to the duplicated net buffer, or NULL if
    287                                 the allocation failed due to resource limit.
    288 
    289 **/
    290 NET_BUF  *
    291 EFIAPI
    292 NetbufDuplicate (
    293   IN NET_BUF                *Nbuf,
    294   IN OUT NET_BUF            *Duplicate        OPTIONAL,
    295   IN UINT32                 HeadSpace
    296   )
    297 {
    298   UINT8                     *Dst;
    299 
    300   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    301 
    302   if (Duplicate == NULL) {
    303     Duplicate = NetbufAlloc (Nbuf->TotalSize + HeadSpace);
    304   }
    305 
    306   if (Duplicate == NULL) {
    307     return NULL;
    308   }
    309 
    310   //
    311   // Don't set the IP and TCP head point, since it is most
    312   // like that they are pointing to the memory of Nbuf.
    313   //
    314   CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
    315   NetbufReserve (Duplicate, HeadSpace);
    316 
    317   Dst = NetbufAllocSpace (Duplicate, Nbuf->TotalSize, NET_BUF_TAIL);
    318   NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dst);
    319 
    320   return Duplicate;
    321 }
    322 
    323 
    324 /**
    325   Free a list of net buffers.
    326 
    327   @param[in, out]  Head              Pointer to the head of linked net buffers.
    328 
    329 **/
    330 VOID
    331 EFIAPI
    332 NetbufFreeList (
    333   IN OUT LIST_ENTRY         *Head
    334   )
    335 {
    336   LIST_ENTRY                *Entry;
    337   LIST_ENTRY                *Next;
    338   NET_BUF                   *Nbuf;
    339 
    340   Entry = Head->ForwardLink;
    341 
    342   NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
    343     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    344     NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    345 
    346     RemoveEntryList (Entry);
    347     NetbufFree (Nbuf);
    348   }
    349 
    350   ASSERT (IsListEmpty (Head));
    351 }
    352 
    353 
    354 /**
    355   Get the index of NET_BLOCK_OP that contains the byte at Offset in the net
    356   buffer.
    357 
    358   This can be used to, for example, retrieve the IP header in the packet. It
    359   also can be used to get the fragment that contains the byte which is used
    360   mainly by the library implementation itself.
    361 
    362   @param[in]   Nbuf      Pointer to the net buffer.
    363   @param[in]   Offset    The offset of the byte.
    364   @param[out]  Index     Index of the NET_BLOCK_OP that contains the byte at
    365                          Offset.
    366 
    367   @return       Pointer to the Offset'th byte of data in the net buffer, or NULL
    368                 if there is no such data in the net buffer.
    369 
    370 **/
    371 UINT8  *
    372 EFIAPI
    373 NetbufGetByte (
    374   IN  NET_BUF               *Nbuf,
    375   IN  UINT32                Offset,
    376   OUT UINT32                *Index  OPTIONAL
    377   )
    378 {
    379   NET_BLOCK_OP              *BlockOp;
    380   UINT32                    Loop;
    381   UINT32                    Len;
    382 
    383   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    384 
    385   if (Offset >= Nbuf->TotalSize) {
    386     return NULL;
    387   }
    388 
    389   BlockOp = Nbuf->BlockOp;
    390   Len     = 0;
    391 
    392   for (Loop = 0; Loop < Nbuf->BlockOpNum; Loop++) {
    393 
    394     if (Len + BlockOp[Loop].Size <= Offset) {
    395       Len += BlockOp[Loop].Size;
    396       continue;
    397     }
    398 
    399     if (Index != NULL) {
    400       *Index = Loop;
    401     }
    402 
    403     return BlockOp[Loop].Head + (Offset - Len);
    404   }
    405 
    406   return NULL;
    407 }
    408 
    409 
    410 
    411 /**
    412   Set the NET_BLOCK and corresponding NET_BLOCK_OP in the net buffer and
    413   corresponding net vector according to the bulk pointer and bulk length.
    414 
    415   All the pointers in the Index'th NET_BLOCK and NET_BLOCK_OP are set to the
    416   bulk's head and tail respectively. So, this function alone can't be used by
    417   NetbufAlloc.
    418 
    419   @param[in, out]  Nbuf       Pointer to the net buffer.
    420   @param[in]       Bulk       Pointer to the data.
    421   @param[in]       Len        Length of the bulk data.
    422   @param[in]       Index      The data block index in the net buffer the bulk
    423                               data should belong to.
    424 
    425 **/
    426 VOID
    427 NetbufSetBlock (
    428   IN OUT NET_BUF            *Nbuf,
    429   IN UINT8                  *Bulk,
    430   IN UINT32                 Len,
    431   IN UINT32                 Index
    432   )
    433 {
    434   NET_BLOCK_OP              *BlockOp;
    435   NET_BLOCK                 *Block;
    436 
    437   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    438   NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
    439   ASSERT (Index < Nbuf->BlockOpNum);
    440 
    441   Block               = &(Nbuf->Vector->Block[Index]);
    442   BlockOp             = &(Nbuf->BlockOp[Index]);
    443   Block->Len          = Len;
    444   Block->Bulk         = Bulk;
    445   BlockOp->BlockHead  = Bulk;
    446   BlockOp->BlockTail  = Bulk + Len;
    447   BlockOp->Head       = Bulk;
    448   BlockOp->Tail       = Bulk + Len;
    449   BlockOp->Size       = Len;
    450 }
    451 
    452 
    453 
    454 /**
    455   Set the NET_BLOCK_OP in the net buffer. The corresponding NET_BLOCK
    456   structure is left untouched.
    457 
    458   Some times, there is no 1:1 relationship between NET_BLOCK and NET_BLOCK_OP.
    459   For example, that in NetbufGetFragment.
    460 
    461   @param[in, out]  Nbuf       Pointer to the net buffer.
    462   @param[in]       Bulk       Pointer to the data.
    463   @param[in]       Len        Length of the bulk data.
    464   @param[in]       Index      The data block index in the net buffer the bulk
    465                               data should belong to.
    466 
    467 **/
    468 VOID
    469 NetbufSetBlockOp (
    470   IN OUT NET_BUF            *Nbuf,
    471   IN UINT8                  *Bulk,
    472   IN UINT32                 Len,
    473   IN UINT32                 Index
    474   )
    475 {
    476   NET_BLOCK_OP              *BlockOp;
    477 
    478   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    479   ASSERT (Index < Nbuf->BlockOpNum);
    480 
    481   BlockOp             = &(Nbuf->BlockOp[Index]);
    482   BlockOp->BlockHead  = Bulk;
    483   BlockOp->BlockTail  = Bulk + Len;
    484   BlockOp->Head       = Bulk;
    485   BlockOp->Tail       = Bulk + Len;
    486   BlockOp->Size       = Len;
    487 }
    488 
    489 
    490 /**
    491   Helper function for NetbufGetFragment. NetbufGetFragment may allocate the
    492   first block to reserve HeadSpace bytes header space. So it needs to create a
    493   new net vector for the first block and can avoid copy for the remaining data
    494   by sharing the old net vector.
    495 
    496   @param[in]  Arg                   Point to the old NET_VECTOR.
    497 
    498 **/
    499 VOID
    500 EFIAPI
    501 NetbufGetFragmentFree (
    502   IN VOID                   *Arg
    503   )
    504 {
    505   NET_VECTOR                *Vector;
    506 
    507   Vector = (NET_VECTOR *)Arg;
    508   NetbufFreeVector (Vector);
    509 }
    510 
    511 
    512 /**
    513   Create a NET_BUF structure which contains Len byte data of Nbuf starting from
    514   Offset.
    515 
    516   A new NET_BUF structure will be created but the associated data in NET_VECTOR
    517   is shared. This function exists to do IP packet fragmentation.
    518 
    519   @param[in]  Nbuf         Pointer to the net buffer to be extracted.
    520   @param[in]  Offset       Starting point of the data to be included in the new
    521                            net buffer.
    522   @param[in]  Len          Bytes of data to be included in the new net buffer.
    523   @param[in]  HeadSpace    Bytes of head space to reserve for protocol header.
    524 
    525   @return                  Pointer to the cloned net buffer, or NULL if the
    526                            allocation failed due to resource limit.
    527 
    528 **/
    529 NET_BUF  *
    530 EFIAPI
    531 NetbufGetFragment (
    532   IN NET_BUF                *Nbuf,
    533   IN UINT32                 Offset,
    534   IN UINT32                 Len,
    535   IN UINT32                 HeadSpace
    536   )
    537 {
    538   NET_BUF                   *Child;
    539   NET_VECTOR                *Vector;
    540   NET_BLOCK_OP              *BlockOp;
    541   UINT32                    CurBlockOp;
    542   UINT32                    BlockOpNum;
    543   UINT8                     *FirstBulk;
    544   UINT32                    Index;
    545   UINT32                    First;
    546   UINT32                    Last;
    547   UINT32                    FirstSkip;
    548   UINT32                    FirstLen;
    549   UINT32                    LastLen;
    550   UINT32                    Cur;
    551 
    552   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    553 
    554   if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {
    555     return NULL;
    556   }
    557 
    558   //
    559   // First find the first and last BlockOp that contains
    560   // the valid data, and compute the offset of the first
    561   // BlockOp and length of the last BlockOp
    562   //
    563   BlockOp = Nbuf->BlockOp;
    564   Cur     = 0;
    565 
    566   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
    567     if (Offset < Cur + BlockOp[Index].Size) {
    568       break;
    569     }
    570 
    571     Cur += BlockOp[Index].Size;
    572   }
    573 
    574   //
    575   // First is the index of the first BlockOp, FirstSkip is
    576   // the offset of the first byte in the first BlockOp.
    577   //
    578   First     = Index;
    579   FirstSkip = Offset - Cur;
    580   FirstLen  = BlockOp[Index].Size - FirstSkip;
    581 
    582   Last      = 0;
    583   LastLen   = 0;
    584 
    585   if (Len > FirstLen) {
    586     Cur += BlockOp[Index].Size;
    587     Index++;
    588 
    589     for (; Index < Nbuf->BlockOpNum; Index++) {
    590       if (Offset + Len <= Cur + BlockOp[Index].Size) {
    591         Last    = Index;
    592         LastLen = Offset + Len - Cur;
    593         break;
    594       }
    595 
    596       Cur += BlockOp[Index].Size;
    597     }
    598 
    599   } else {
    600     Last     = First;
    601     LastLen  = Len;
    602     FirstLen = Len;
    603   }
    604 
    605   ASSERT (Last >= First);
    606   BlockOpNum = Last - First + 1;
    607   CurBlockOp = 0;
    608 
    609   if (HeadSpace != 0) {
    610     //
    611     // Allocate an extra block to accomdate the head space.
    612     //
    613     BlockOpNum++;
    614 
    615     Child = NetbufAllocStruct (1, BlockOpNum);
    616 
    617     if (Child == NULL) {
    618       return NULL;
    619     }
    620 
    621     FirstBulk = AllocatePool (HeadSpace);
    622 
    623     if (FirstBulk == NULL) {
    624       goto FreeChild;
    625     }
    626 
    627     Vector        = Child->Vector;
    628     Vector->Free  = NetbufGetFragmentFree;
    629     Vector->Arg   = Nbuf->Vector;
    630     Vector->Flag  = NET_VECTOR_OWN_FIRST;
    631     Vector->Len   = HeadSpace;
    632 
    633     //
    634     // Reserve the head space in the first block
    635     //
    636     NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);
    637     Child->BlockOp[0].Head += HeadSpace;
    638     Child->BlockOp[0].Size =  0;
    639     CurBlockOp++;
    640 
    641   } else {
    642     Child = NetbufAllocStruct (0, BlockOpNum);
    643 
    644     if (Child == NULL) {
    645       return NULL;
    646     }
    647 
    648     Child->Vector = Nbuf->Vector;
    649   }
    650 
    651   NET_GET_REF (Nbuf->Vector);
    652   Child->TotalSize = Len;
    653 
    654   //
    655   // Set all the BlockOp up, the first and last one are special
    656   // and need special process.
    657   //
    658   NetbufSetBlockOp (
    659     Child,
    660     Nbuf->BlockOp[First].Head + FirstSkip,
    661     FirstLen,
    662     CurBlockOp++
    663     );
    664 
    665   for (Index = First + 1; Index < Last; Index++) {
    666     NetbufSetBlockOp (
    667       Child,
    668       BlockOp[Index].Head,
    669       BlockOp[Index].Size,
    670       CurBlockOp++
    671       );
    672   }
    673 
    674   if (First != Last) {
    675     NetbufSetBlockOp (
    676       Child,
    677       BlockOp[Last].Head,
    678       LastLen,
    679       CurBlockOp
    680       );
    681   }
    682 
    683   CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
    684   return Child;
    685 
    686 FreeChild:
    687 
    688   FreePool (Child);
    689   return NULL;
    690 }
    691 
    692 
    693 
    694 /**
    695   Build a NET_BUF from external blocks.
    696 
    697   A new NET_BUF structure will be created from external blocks. Additional block
    698   of memory will be allocated to hold reserved HeadSpace bytes of header room
    699   and existing HeadLen bytes of header but the external blocks are shared by the
    700   net buffer to avoid data copying.
    701 
    702   @param[in]  ExtFragment           Pointer to the data block.
    703   @param[in]  ExtNum                The number of the data blocks.
    704   @param[in]  HeadSpace             The head space to be reserved.
    705   @param[in]  HeadLen               The length of the protocol header, This function
    706                                     will pull that number of data into a linear block.
    707   @param[in]  ExtFree               Pointer to the caller provided free function.
    708   @param[in]  Arg                   The argument passed to ExtFree when ExtFree is
    709                                     called.
    710 
    711   @return                  Pointer to the net buffer built from the data blocks,
    712                            or NULL if the allocation failed due to resource
    713                            limit.
    714 
    715 **/
    716 NET_BUF  *
    717 EFIAPI
    718 NetbufFromExt (
    719   IN NET_FRAGMENT           *ExtFragment,
    720   IN UINT32                 ExtNum,
    721   IN UINT32                 HeadSpace,
    722   IN UINT32                 HeadLen,
    723   IN NET_VECTOR_EXT_FREE    ExtFree,
    724   IN VOID                   *Arg          OPTIONAL
    725   )
    726 {
    727   NET_BUF                   *Nbuf;
    728   NET_VECTOR                *Vector;
    729   NET_FRAGMENT              SavedFragment;
    730   UINT32                    SavedIndex;
    731   UINT32                    TotalLen;
    732   UINT32                    BlockNum;
    733   UINT8                     *FirstBlock;
    734   UINT32                    FirstBlockLen;
    735   UINT8                     *Header;
    736   UINT32                    CurBlock;
    737   UINT32                    Index;
    738   UINT32                    Len;
    739   UINT32                    Copied;
    740 
    741   ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));
    742 
    743   SavedFragment.Bulk = NULL;
    744   SavedFragment.Len  = 0;
    745 
    746   FirstBlockLen  = 0;
    747   FirstBlock     = NULL;
    748   BlockNum       = ExtNum;
    749   Index          = 0;
    750   TotalLen       = 0;
    751   SavedIndex     = 0;
    752   Len            = 0;
    753   Copied         = 0;
    754 
    755   //
    756   // No need to consolidate the header if the first block is
    757   // longer than the header length or there is only one block.
    758   //
    759   if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {
    760     HeadLen = 0;
    761   }
    762 
    763   //
    764   // Allocate an extra block if we need to:
    765   //  1. Allocate some header space
    766   //  2. aggreate the packet header
    767   //
    768   if ((HeadSpace != 0) || (HeadLen != 0)) {
    769     FirstBlockLen = HeadLen + HeadSpace;
    770     FirstBlock    = AllocatePool (FirstBlockLen);
    771 
    772     if (FirstBlock == NULL) {
    773       return NULL;
    774     }
    775 
    776     BlockNum++;
    777   }
    778 
    779   //
    780   // Copy the header to the first block, reduce the NET_BLOCK
    781   // to allocate by one for each block that is completely covered
    782   // by the first bulk.
    783   //
    784   if (HeadLen != 0) {
    785     Len    = HeadLen;
    786     Header = FirstBlock + HeadSpace;
    787 
    788     for (Index = 0; Index < ExtNum; Index++) {
    789       if (Len >= ExtFragment[Index].Len) {
    790         CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);
    791 
    792         Copied    += ExtFragment[Index].Len;
    793         Len       -= ExtFragment[Index].Len;
    794         Header    += ExtFragment[Index].Len;
    795         TotalLen  += ExtFragment[Index].Len;
    796         BlockNum--;
    797 
    798         if (Len == 0) {
    799           //
    800           // Increament the index number to point to the next
    801           // non-empty fragment.
    802           //
    803           Index++;
    804           break;
    805         }
    806 
    807       } else {
    808         CopyMem (Header, ExtFragment[Index].Bulk, Len);
    809 
    810         Copied    += Len;
    811         TotalLen  += Len;
    812 
    813         //
    814         // Adjust the block structure to exclude the data copied,
    815         // So, the left-over block can be processed as other blocks.
    816         // But it must be recovered later. (SavedIndex > 0) always
    817         // holds since we don't aggreate the header if the first block
    818         // is bigger enough that the header is continuous
    819         //
    820         SavedIndex    = Index;
    821         SavedFragment = ExtFragment[Index];
    822         ExtFragment[Index].Bulk += Len;
    823         ExtFragment[Index].Len  -= Len;
    824         break;
    825       }
    826     }
    827   }
    828 
    829   Nbuf = NetbufAllocStruct (BlockNum, BlockNum);
    830 
    831   if (Nbuf == NULL) {
    832     goto FreeFirstBlock;
    833   }
    834 
    835   Vector       = Nbuf->Vector;
    836   Vector->Free = ExtFree;
    837   Vector->Arg  = Arg;
    838   Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);
    839 
    840   //
    841   // Set the first block up which may contain
    842   // some head space and aggregated header
    843   //
    844   CurBlock = 0;
    845 
    846   if (FirstBlockLen != 0) {
    847     NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);
    848     Nbuf->BlockOp[0].Head += HeadSpace;
    849     Nbuf->BlockOp[0].Size =  Copied;
    850 
    851     CurBlock++;
    852   }
    853 
    854   for (; Index < ExtNum; Index++) {
    855     NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);
    856     TotalLen += ExtFragment[Index].Len;
    857     CurBlock++;
    858   }
    859 
    860   Vector->Len     = TotalLen + HeadSpace;
    861   Nbuf->TotalSize = TotalLen;
    862 
    863   if (SavedIndex != 0) {
    864     ExtFragment[SavedIndex] = SavedFragment;
    865   }
    866 
    867   return Nbuf;
    868 
    869 FreeFirstBlock:
    870   if (FirstBlock != NULL) {
    871     FreePool (FirstBlock);
    872   }
    873   return NULL;
    874 }
    875 
    876 
    877 /**
    878   Build a fragment table to contain the fragments in the net buffer. This is the
    879   opposite operation of the NetbufFromExt.
    880 
    881   @param[in]       Nbuf                  Point to the net buffer.
    882   @param[in, out]  ExtFragment           Pointer to the data block.
    883   @param[in, out]  ExtNum                The number of the data blocks.
    884 
    885   @retval EFI_BUFFER_TOO_SMALL  The number of non-empty block is bigger than
    886                                 ExtNum.
    887   @retval EFI_SUCCESS           Fragment table is built successfully.
    888 
    889 **/
    890 EFI_STATUS
    891 EFIAPI
    892 NetbufBuildExt (
    893   IN NET_BUF                *Nbuf,
    894   IN OUT NET_FRAGMENT       *ExtFragment,
    895   IN OUT UINT32             *ExtNum
    896   )
    897 {
    898   UINT32                    Index;
    899   UINT32                    Current;
    900 
    901   Current = 0;
    902 
    903   for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {
    904     if (Nbuf->BlockOp[Index].Size == 0) {
    905       continue;
    906     }
    907 
    908     if (Current < *ExtNum) {
    909       ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
    910       ExtFragment[Current].Len  = Nbuf->BlockOp[Index].Size;
    911       Current++;
    912     } else {
    913       return EFI_BUFFER_TOO_SMALL;
    914     }
    915   }
    916 
    917   *ExtNum = Current;
    918   return EFI_SUCCESS;
    919 }
    920 
    921 
    922 /**
    923   Build a net buffer from a list of net buffers.
    924 
    925   All the fragments will be collected from the list of NEW_BUF and then a new
    926   net buffer will be created through NetbufFromExt.
    927 
    928   @param[in]   BufList    A List of the net buffer.
    929   @param[in]   HeadSpace  The head space to be reserved.
    930   @param[in]   HeaderLen  The length of the protocol header, This function
    931                           will pull that number of data into a linear block.
    932   @param[in]   ExtFree    Pointer to the caller provided free function.
    933   @param[in]   Arg        The argument passed to ExtFree when ExtFree is called.
    934 
    935   @return                 Pointer to the net buffer built from the list of net
    936                           buffers.
    937 
    938 **/
    939 NET_BUF  *
    940 EFIAPI
    941 NetbufFromBufList (
    942   IN LIST_ENTRY             *BufList,
    943   IN UINT32                 HeadSpace,
    944   IN UINT32                 HeaderLen,
    945   IN NET_VECTOR_EXT_FREE    ExtFree,
    946   IN VOID                   *Arg              OPTIONAL
    947   )
    948 {
    949   NET_FRAGMENT              *Fragment;
    950   UINT32                    FragmentNum;
    951   LIST_ENTRY                *Entry;
    952   NET_BUF                   *Nbuf;
    953   UINT32                    Index;
    954   UINT32                    Current;
    955 
    956   //
    957   //Compute how many blocks are there
    958   //
    959   FragmentNum = 0;
    960 
    961   NET_LIST_FOR_EACH (Entry, BufList) {
    962     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    963     NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    964     FragmentNum += Nbuf->BlockOpNum;
    965   }
    966 
    967   //
    968   //Allocate and copy block points
    969   //
    970   Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);
    971 
    972   if (Fragment == NULL) {
    973     return NULL;
    974   }
    975 
    976   Current = 0;
    977 
    978   NET_LIST_FOR_EACH (Entry, BufList) {
    979     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    980     NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    981 
    982     for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
    983       if (Nbuf->BlockOp[Index].Size != 0) {
    984         Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
    985         Fragment[Current].Len  = Nbuf->BlockOp[Index].Size;
    986         Current++;
    987       }
    988     }
    989   }
    990 
    991   Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);
    992   FreePool (Fragment);
    993 
    994   return Nbuf;
    995 }
    996 
    997 
    998 /**
    999   Reserve some space in the header room of the net buffer.
   1000 
   1001   Upon allocation, all the space are in the tail room of the buffer. Call this
   1002   function to move some space to the header room. This function is quite limited
   1003   in that it can only reserve space from the first block of an empty NET_BUF not
   1004   built from the external. But it should be enough for the network stack.
   1005 
   1006   @param[in, out]  Nbuf     Pointer to the net buffer.
   1007   @param[in]       Len      The length of buffer to be reserved from the header.
   1008 
   1009 **/
   1010 VOID
   1011 EFIAPI
   1012 NetbufReserve (
   1013   IN OUT NET_BUF            *Nbuf,
   1014   IN UINT32                 Len
   1015   )
   1016 {
   1017   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1018   NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
   1019 
   1020   ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));
   1021   ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));
   1022 
   1023   Nbuf->BlockOp[0].Head += Len;
   1024   Nbuf->BlockOp[0].Tail += Len;
   1025 
   1026   ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);
   1027 }
   1028 
   1029 
   1030 /**
   1031   Allocate Len bytes of space from the header or tail of the buffer.
   1032 
   1033   @param[in, out]  Nbuf       Pointer to the net buffer.
   1034   @param[in]       Len        The length of the buffer to be allocated.
   1035   @param[in]       FromHead   The flag to indicate whether reserve the data
   1036                               from head (TRUE) or tail (FALSE).
   1037 
   1038   @return                     Pointer to the first byte of the allocated buffer,
   1039                               or NULL if there is no sufficient space.
   1040 
   1041 **/
   1042 UINT8*
   1043 EFIAPI
   1044 NetbufAllocSpace (
   1045   IN OUT NET_BUF            *Nbuf,
   1046   IN UINT32                 Len,
   1047   IN BOOLEAN                FromHead
   1048   )
   1049 {
   1050   NET_BLOCK_OP              *BlockOp;
   1051   UINT32                    Index;
   1052   UINT8                     *SavedTail;
   1053 
   1054   Index = 0;
   1055 
   1056   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1057   NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
   1058 
   1059   ASSERT (Len > 0);
   1060 
   1061   if (FromHead) {
   1062     //
   1063     // Allocate some space from head. If the buffer is empty,
   1064     // allocate from the first block. If it isn't, allocate
   1065     // from the first non-empty block, or the block before that.
   1066     //
   1067     if (Nbuf->TotalSize == 0) {
   1068       Index = 0;
   1069     } else {
   1070       NetbufGetByte (Nbuf, 0, &Index);
   1071 
   1072       if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
   1073         Index--;
   1074       }
   1075     }
   1076 
   1077     BlockOp = &(Nbuf->BlockOp[Index]);
   1078 
   1079     if (NET_HEADSPACE (BlockOp) < Len) {
   1080       return NULL;
   1081     }
   1082 
   1083     BlockOp->Head   -= Len;
   1084     BlockOp->Size   += Len;
   1085     Nbuf->TotalSize += Len;
   1086 
   1087     return BlockOp->Head;
   1088 
   1089   } else {
   1090     //
   1091     // Allocate some space from the tail. If the buffer is empty,
   1092     // allocate from the first block. If it isn't, allocate
   1093     // from the last non-empty block, or the block after that.
   1094     //
   1095     if (Nbuf->TotalSize == 0) {
   1096       Index = 0;
   1097     } else {
   1098       NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
   1099 
   1100       if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
   1101           (Index < Nbuf->BlockOpNum - 1)) {
   1102 
   1103         Index++;
   1104       }
   1105     }
   1106 
   1107     BlockOp = &(Nbuf->BlockOp[Index]);
   1108 
   1109     if (NET_TAILSPACE (BlockOp) < Len) {
   1110       return NULL;
   1111     }
   1112 
   1113     SavedTail       = BlockOp->Tail;
   1114 
   1115     BlockOp->Tail   += Len;
   1116     BlockOp->Size   += Len;
   1117     Nbuf->TotalSize += Len;
   1118 
   1119     return SavedTail;
   1120   }
   1121 }
   1122 
   1123 
   1124 /**
   1125   Trim a single NET_BLOCK by Len bytes from the header or tail.
   1126 
   1127   @param[in, out]  BlockOp      Pointer to the NET_BLOCK.
   1128   @param[in]       Len          The length of the data to be trimmed.
   1129   @param[in]       FromHead     The flag to indicate whether trim data from head
   1130                                 (TRUE) or tail (FALSE).
   1131 
   1132 **/
   1133 VOID
   1134 NetblockTrim (
   1135   IN OUT NET_BLOCK_OP       *BlockOp,
   1136   IN UINT32                 Len,
   1137   IN BOOLEAN                FromHead
   1138   )
   1139 {
   1140   ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));
   1141 
   1142   BlockOp->Size -= Len;
   1143 
   1144   if (FromHead) {
   1145     BlockOp->Head += Len;
   1146   } else {
   1147     BlockOp->Tail -= Len;
   1148   }
   1149 }
   1150 
   1151 
   1152 /**
   1153   Trim Len bytes from the header or tail of the net buffer.
   1154 
   1155   @param[in, out]  Nbuf         Pointer to the net buffer.
   1156   @param[in]       Len          The length of the data to be trimmed.
   1157   @param[in]      FromHead      The flag to indicate whether trim data from head
   1158                                 (TRUE) or tail (FALSE).
   1159 
   1160   @return    Length of the actually trimmed data, which is possible to be less
   1161              than Len because the TotalSize of Nbuf is less than Len.
   1162 
   1163 **/
   1164 UINT32
   1165 EFIAPI
   1166 NetbufTrim (
   1167   IN OUT NET_BUF            *Nbuf,
   1168   IN UINT32                 Len,
   1169   IN BOOLEAN                FromHead
   1170   )
   1171 {
   1172   NET_BLOCK_OP              *BlockOp;
   1173   UINT32                    Index;
   1174   UINT32                    Trimmed;
   1175 
   1176   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1177 
   1178   if (Len > Nbuf->TotalSize) {
   1179     Len = Nbuf->TotalSize;
   1180   }
   1181 
   1182   //
   1183   // If FromTail is true, iterate backward. That
   1184   // is, init Index to NBuf->BlockNum - 1, and
   1185   // decrease it by 1 during each loop. Otherwise,
   1186   // iterate forward. That is, init Index to 0, and
   1187   // increase it by 1 during each loop.
   1188   //
   1189   Trimmed          = 0;
   1190   Nbuf->TotalSize -= Len;
   1191 
   1192   Index   = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
   1193   BlockOp = Nbuf->BlockOp;
   1194 
   1195   for (;;) {
   1196     if (BlockOp[Index].Size == 0) {
   1197       Index += (FromHead ? 1 : -1);
   1198       continue;
   1199     }
   1200 
   1201     if (Len > BlockOp[Index].Size) {
   1202       Len     -= BlockOp[Index].Size;
   1203       Trimmed += BlockOp[Index].Size;
   1204       NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
   1205     } else {
   1206       Trimmed += Len;
   1207       NetblockTrim (&BlockOp[Index], Len, FromHead);
   1208       break;
   1209     }
   1210 
   1211     Index += (FromHead ? 1 : -1);
   1212   }
   1213 
   1214   return Trimmed;
   1215 }
   1216 
   1217 
   1218 /**
   1219   Copy Len bytes of data from the specific offset of the net buffer to the
   1220   destination memory.
   1221 
   1222   The Len bytes of data may cross the several fragments of the net buffer.
   1223 
   1224   @param[in]   Nbuf         Pointer to the net buffer.
   1225   @param[in]   Offset       The sequence number of the first byte to copy.
   1226   @param[in]   Len          Length of the data to copy.
   1227   @param[in]   Dest         The destination of the data to copy to.
   1228 
   1229   @return           The length of the actual copied data, or 0 if the offset
   1230                     specified exceeds the total size of net buffer.
   1231 
   1232 **/
   1233 UINT32
   1234 EFIAPI
   1235 NetbufCopy (
   1236   IN NET_BUF                *Nbuf,
   1237   IN UINT32                 Offset,
   1238   IN UINT32                 Len,
   1239   IN UINT8                  *Dest
   1240   )
   1241 {
   1242   NET_BLOCK_OP              *BlockOp;
   1243   UINT32                    Skip;
   1244   UINT32                    Left;
   1245   UINT32                    Copied;
   1246   UINT32                    Index;
   1247   UINT32                    Cur;
   1248 
   1249   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1250   ASSERT (Dest);
   1251 
   1252   if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
   1253     return 0;
   1254   }
   1255 
   1256   if (Nbuf->TotalSize - Offset < Len) {
   1257     Len = Nbuf->TotalSize - Offset;
   1258   }
   1259 
   1260   BlockOp = Nbuf->BlockOp;
   1261 
   1262   //
   1263   // Skip to the offset. Don't make "Offset-By-One" error here.
   1264   // Cur + BLOCK.SIZE is the first sequence number of next block.
   1265   // So, (Offset < Cur + BLOCK.SIZE) means that the  first byte
   1266   // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
   1267   // first byte is the next block's first byte.
   1268   //
   1269   Cur = 0;
   1270 
   1271   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
   1272     if (BlockOp[Index].Size == 0) {
   1273       continue;
   1274     }
   1275 
   1276     if (Offset < Cur + BlockOp[Index].Size) {
   1277       break;
   1278     }
   1279 
   1280     Cur += BlockOp[Index].Size;
   1281   }
   1282 
   1283   //
   1284   // Cur is the sequence number of the first byte in the block
   1285   // Offset - Cur is the number of bytes before first byte to
   1286   // to copy in the current block.
   1287   //
   1288   Skip  = Offset - Cur;
   1289   Left  = BlockOp[Index].Size - Skip;
   1290 
   1291   if (Len <= Left) {
   1292     CopyMem (Dest, BlockOp[Index].Head + Skip, Len);
   1293     return Len;
   1294   }
   1295 
   1296   CopyMem (Dest, BlockOp[Index].Head + Skip, Left);
   1297 
   1298   Dest  += Left;
   1299   Len   -= Left;
   1300   Copied = Left;
   1301 
   1302   Index++;
   1303 
   1304   for (; Index < Nbuf->BlockOpNum; Index++) {
   1305     if (Len > BlockOp[Index].Size) {
   1306       Len    -= BlockOp[Index].Size;
   1307       Copied += BlockOp[Index].Size;
   1308 
   1309       CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
   1310       Dest   += BlockOp[Index].Size;
   1311     } else {
   1312       Copied += Len;
   1313       CopyMem (Dest, BlockOp[Index].Head, Len);
   1314       break;
   1315     }
   1316   }
   1317 
   1318   return Copied;
   1319 }
   1320 
   1321 
   1322 /**
   1323   Initiate the net buffer queue.
   1324 
   1325   @param[in, out]  NbufQue   Pointer to the net buffer queue to be initialized.
   1326 
   1327 **/
   1328 VOID
   1329 EFIAPI
   1330 NetbufQueInit (
   1331   IN OUT NET_BUF_QUEUE          *NbufQue
   1332   )
   1333 {
   1334   NbufQue->Signature  = NET_QUE_SIGNATURE;
   1335   NbufQue->RefCnt     = 1;
   1336   InitializeListHead (&NbufQue->List);
   1337 
   1338   InitializeListHead (&NbufQue->BufList);
   1339   NbufQue->BufSize  = 0;
   1340   NbufQue->BufNum   = 0;
   1341 }
   1342 
   1343 
   1344 /**
   1345   Allocate and initialize a net buffer queue.
   1346 
   1347   @return         Pointer to the allocated net buffer queue, or NULL if the
   1348                   allocation failed due to resource limit.
   1349 
   1350 **/
   1351 NET_BUF_QUEUE  *
   1352 EFIAPI
   1353 NetbufQueAlloc (
   1354   VOID
   1355   )
   1356 {
   1357   NET_BUF_QUEUE             *NbufQue;
   1358 
   1359   NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));
   1360   if (NbufQue == NULL) {
   1361     return NULL;
   1362   }
   1363 
   1364   NetbufQueInit (NbufQue);
   1365 
   1366   return NbufQue;
   1367 }
   1368 
   1369 
   1370 /**
   1371   Free a net buffer queue.
   1372 
   1373   Decrease the reference count of the net buffer queue by one. The real resource
   1374   free operation isn't performed until the reference count of the net buffer
   1375   queue is decreased to 0.
   1376 
   1377   @param[in]  NbufQue               Pointer to the net buffer queue to be freed.
   1378 
   1379 **/
   1380 VOID
   1381 EFIAPI
   1382 NetbufQueFree (
   1383   IN NET_BUF_QUEUE          *NbufQue
   1384   )
   1385 {
   1386   ASSERT (NbufQue != NULL);
   1387   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1388 
   1389   NbufQue->RefCnt--;
   1390 
   1391   if (NbufQue->RefCnt == 0) {
   1392     NetbufQueFlush (NbufQue);
   1393     FreePool (NbufQue);
   1394   }
   1395 }
   1396 
   1397 
   1398 /**
   1399   Append a net buffer to the net buffer queue.
   1400 
   1401   @param[in, out]  NbufQue            Pointer to the net buffer queue.
   1402   @param[in, out]  Nbuf               Pointer to the net buffer to be appended.
   1403 
   1404 **/
   1405 VOID
   1406 EFIAPI
   1407 NetbufQueAppend (
   1408   IN OUT NET_BUF_QUEUE          *NbufQue,
   1409   IN OUT NET_BUF                *Nbuf
   1410   )
   1411 {
   1412   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1413   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1414 
   1415   InsertTailList (&NbufQue->BufList, &Nbuf->List);
   1416 
   1417   NbufQue->BufSize += Nbuf->TotalSize;
   1418   NbufQue->BufNum++;
   1419 }
   1420 
   1421 
   1422 /**
   1423   Remove a net buffer from the head in the specific queue and return it.
   1424 
   1425   @param[in, out]  NbufQue               Pointer to the net buffer queue.
   1426 
   1427   @return           Pointer to the net buffer removed from the specific queue,
   1428                     or NULL if there is no net buffer in the specific queue.
   1429 
   1430 **/
   1431 NET_BUF  *
   1432 EFIAPI
   1433 NetbufQueRemove (
   1434   IN OUT NET_BUF_QUEUE          *NbufQue
   1435   )
   1436 {
   1437   NET_BUF                   *First;
   1438 
   1439   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1440 
   1441   if (NbufQue->BufNum == 0) {
   1442     return NULL;
   1443   }
   1444 
   1445   First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
   1446 
   1447   NetListRemoveHead (&NbufQue->BufList);
   1448 
   1449   NbufQue->BufSize -= First->TotalSize;
   1450   NbufQue->BufNum--;
   1451   return First;
   1452 }
   1453 
   1454 
   1455 /**
   1456   Copy Len bytes of data from the net buffer queue at the specific offset to the
   1457   destination memory.
   1458 
   1459   The copying operation is the same as NetbufCopy but applies to the net buffer
   1460   queue instead of the net buffer.
   1461 
   1462   @param[in]   NbufQue         Pointer to the net buffer queue.
   1463   @param[in]   Offset          The sequence number of the first byte to copy.
   1464   @param[in]   Len             Length of the data to copy.
   1465   @param[out]  Dest            The destination of the data to copy to.
   1466 
   1467   @return       The length of the actual copied data, or 0 if the offset
   1468                 specified exceeds the total size of net buffer queue.
   1469 
   1470 **/
   1471 UINT32
   1472 EFIAPI
   1473 NetbufQueCopy (
   1474   IN NET_BUF_QUEUE          *NbufQue,
   1475   IN UINT32                 Offset,
   1476   IN UINT32                 Len,
   1477   OUT UINT8                 *Dest
   1478   )
   1479 {
   1480   LIST_ENTRY                *Entry;
   1481   NET_BUF                   *Nbuf;
   1482   UINT32                    Skip;
   1483   UINT32                    Left;
   1484   UINT32                    Cur;
   1485   UINT32                    Copied;
   1486 
   1487   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1488   ASSERT (Dest != NULL);
   1489 
   1490   if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
   1491     return 0;
   1492   }
   1493 
   1494   if (NbufQue->BufSize - Offset < Len) {
   1495     Len = NbufQue->BufSize - Offset;
   1496   }
   1497 
   1498   //
   1499   // skip to the Offset
   1500   //
   1501   Cur   = 0;
   1502   Nbuf  = NULL;
   1503 
   1504   NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
   1505     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
   1506 
   1507     if (Offset < Cur + Nbuf->TotalSize) {
   1508       break;
   1509     }
   1510 
   1511     Cur += Nbuf->TotalSize;
   1512   }
   1513 
   1514   ASSERT (Nbuf != NULL);
   1515 
   1516   //
   1517   // Copy the data in the first buffer.
   1518   //
   1519   Skip  = Offset - Cur;
   1520   Left  = Nbuf->TotalSize - Skip;
   1521 
   1522   if (Len < Left) {
   1523     return NetbufCopy (Nbuf, Skip, Len, Dest);
   1524   }
   1525 
   1526   NetbufCopy (Nbuf, Skip, Left, Dest);
   1527   Dest  += Left;
   1528   Len   -= Left;
   1529   Copied = Left;
   1530 
   1531   //
   1532   // Iterate over the others
   1533   //
   1534   Entry = Entry->ForwardLink;
   1535 
   1536   while ((Len > 0) && (Entry != &NbufQue->BufList)) {
   1537     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
   1538 
   1539     if (Len > Nbuf->TotalSize) {
   1540       Len -= Nbuf->TotalSize;
   1541       Copied += Nbuf->TotalSize;
   1542 
   1543       NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
   1544       Dest += Nbuf->TotalSize;
   1545 
   1546     } else {
   1547       NetbufCopy (Nbuf, 0, Len, Dest);
   1548       Copied += Len;
   1549       break;
   1550     }
   1551 
   1552     Entry = Entry->ForwardLink;
   1553   }
   1554 
   1555   return Copied;
   1556 }
   1557 
   1558 
   1559 /**
   1560   Trim Len bytes of data from the buffer queue and free any net buffer
   1561   that is completely trimmed.
   1562 
   1563   The trimming operation is the same as NetbufTrim but applies to the net buffer
   1564   queue instead of the net buffer.
   1565 
   1566   @param[in, out]  NbufQue               Pointer to the net buffer queue.
   1567   @param[in]       Len                   Length of the data to trim.
   1568 
   1569   @return   The actual length of the data trimmed.
   1570 
   1571 **/
   1572 UINT32
   1573 EFIAPI
   1574 NetbufQueTrim (
   1575   IN OUT NET_BUF_QUEUE      *NbufQue,
   1576   IN UINT32                 Len
   1577   )
   1578 {
   1579   LIST_ENTRY                *Entry;
   1580   LIST_ENTRY                *Next;
   1581   NET_BUF                   *Nbuf;
   1582   UINT32                    Trimmed;
   1583 
   1584   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1585 
   1586   if (Len == 0) {
   1587     return 0;
   1588   }
   1589 
   1590   if (Len > NbufQue->BufSize) {
   1591     Len = NbufQue->BufSize;
   1592   }
   1593 
   1594   NbufQue->BufSize -= Len;
   1595   Trimmed = 0;
   1596 
   1597   NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
   1598     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
   1599 
   1600     if (Len >= Nbuf->TotalSize) {
   1601       Trimmed += Nbuf->TotalSize;
   1602       Len -= Nbuf->TotalSize;
   1603 
   1604       RemoveEntryList (Entry);
   1605       NetbufFree (Nbuf);
   1606 
   1607       NbufQue->BufNum--;
   1608 
   1609       if (Len == 0) {
   1610         break;
   1611       }
   1612 
   1613     } else {
   1614       Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
   1615       break;
   1616     }
   1617   }
   1618 
   1619   return Trimmed;
   1620 }
   1621 
   1622 
   1623 /**
   1624   Flush the net buffer queue.
   1625 
   1626   @param[in, out]  NbufQue               Pointer to the queue to be flushed.
   1627 
   1628 **/
   1629 VOID
   1630 EFIAPI
   1631 NetbufQueFlush (
   1632   IN OUT NET_BUF_QUEUE          *NbufQue
   1633   )
   1634 {
   1635   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
   1636 
   1637   NetbufFreeList (&NbufQue->BufList);
   1638 
   1639   NbufQue->BufNum   = 0;
   1640   NbufQue->BufSize  = 0;
   1641 }
   1642 
   1643 
   1644 /**
   1645   Compute the checksum for a bulk of data.
   1646 
   1647   @param[in]   Bulk                  Pointer to the data.
   1648   @param[in]   Len                   Length of the data, in bytes.
   1649 
   1650   @return    The computed checksum.
   1651 
   1652 **/
   1653 UINT16
   1654 EFIAPI
   1655 NetblockChecksum (
   1656   IN UINT8                  *Bulk,
   1657   IN UINT32                 Len
   1658   )
   1659 {
   1660   register UINT32           Sum;
   1661 
   1662   Sum = 0;
   1663 
   1664   //
   1665   // Add left-over byte, if any
   1666   //
   1667   if (Len % 2 != 0) {
   1668     Sum += *(Bulk + Len - 1);
   1669   }
   1670 
   1671   while (Len > 1) {
   1672     Sum += *(UINT16 *) Bulk;
   1673     Bulk += 2;
   1674     Len -= 2;
   1675   }
   1676 
   1677   //
   1678   // Fold 32-bit sum to 16 bits
   1679   //
   1680   while ((Sum >> 16) != 0) {
   1681     Sum = (Sum & 0xffff) + (Sum >> 16);
   1682 
   1683   }
   1684 
   1685   return (UINT16) Sum;
   1686 }
   1687 
   1688 
   1689 /**
   1690   Add two checksums.
   1691 
   1692   @param[in]   Checksum1             The first checksum to be added.
   1693   @param[in]   Checksum2             The second checksum to be added.
   1694 
   1695   @return         The new checksum.
   1696 
   1697 **/
   1698 UINT16
   1699 EFIAPI
   1700 NetAddChecksum (
   1701   IN UINT16                 Checksum1,
   1702   IN UINT16                 Checksum2
   1703   )
   1704 {
   1705   UINT32                    Sum;
   1706 
   1707   Sum = Checksum1 + Checksum2;
   1708 
   1709   //
   1710   // two UINT16 can only add up to a carry of 1.
   1711   //
   1712   if ((Sum >> 16) != 0) {
   1713     Sum = (Sum & 0xffff) + 1;
   1714 
   1715   }
   1716 
   1717   return (UINT16) Sum;
   1718 }
   1719 
   1720 
   1721 /**
   1722   Compute the checksum for a NET_BUF.
   1723 
   1724   @param[in]   Nbuf                  Pointer to the net buffer.
   1725 
   1726   @return    The computed checksum.
   1727 
   1728 **/
   1729 UINT16
   1730 EFIAPI
   1731 NetbufChecksum (
   1732   IN NET_BUF                *Nbuf
   1733   )
   1734 {
   1735   NET_BLOCK_OP              *BlockOp;
   1736   UINT32                    Offset;
   1737   UINT16                    TotalSum;
   1738   UINT16                    BlockSum;
   1739   UINT32                    Index;
   1740 
   1741   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1742 
   1743   TotalSum  = 0;
   1744   Offset    = 0;
   1745   BlockOp   = Nbuf->BlockOp;
   1746 
   1747   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
   1748     if (BlockOp[Index].Size == 0) {
   1749       continue;
   1750     }
   1751 
   1752     BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
   1753 
   1754     if ((Offset & 0x01) != 0) {
   1755       //
   1756       // The checksum starts with an odd byte, swap
   1757       // the checksum before added to total checksum
   1758       //
   1759       BlockSum = SwapBytes16 (BlockSum);
   1760     }
   1761 
   1762     TotalSum = NetAddChecksum (BlockSum, TotalSum);
   1763     Offset  += BlockOp[Index].Size;
   1764   }
   1765 
   1766   return TotalSum;
   1767 }
   1768 
   1769 
   1770 /**
   1771   Compute the checksum for TCP/UDP pseudo header.
   1772 
   1773   Src and Dst are in network byte order, and Len is in host byte order.
   1774 
   1775   @param[in]   Src                   The source address of the packet.
   1776   @param[in]   Dst                   The destination address of the packet.
   1777   @param[in]   Proto                 The protocol type of the packet.
   1778   @param[in]   Len                   The length of the packet.
   1779 
   1780   @return   The computed checksum.
   1781 
   1782 **/
   1783 UINT16
   1784 EFIAPI
   1785 NetPseudoHeadChecksum (
   1786   IN IP4_ADDR               Src,
   1787   IN IP4_ADDR               Dst,
   1788   IN UINT8                  Proto,
   1789   IN UINT16                 Len
   1790   )
   1791 {
   1792   NET_PSEUDO_HDR            Hdr;
   1793 
   1794   //
   1795   // Zero the memory to relieve align problems
   1796   //
   1797   ZeroMem (&Hdr, sizeof (Hdr));
   1798 
   1799   Hdr.SrcIp     = Src;
   1800   Hdr.DstIp     = Dst;
   1801   Hdr.Protocol  = Proto;
   1802   Hdr.Len       = HTONS (Len);
   1803 
   1804   return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
   1805 }
   1806 
   1807 /**
   1808   Compute the checksum for TCP6/UDP6 pseudo header.
   1809 
   1810   Src and Dst are in network byte order, and Len is in host byte order.
   1811 
   1812   @param[in]   Src                   The source address of the packet.
   1813   @param[in]   Dst                   The destination address of the packet.
   1814   @param[in]   NextHeader            The protocol type of the packet.
   1815   @param[in]   Len                   The length of the packet.
   1816 
   1817   @return   The computed checksum.
   1818 
   1819 **/
   1820 UINT16
   1821 EFIAPI
   1822 NetIp6PseudoHeadChecksum (
   1823   IN EFI_IPv6_ADDRESS       *Src,
   1824   IN EFI_IPv6_ADDRESS       *Dst,
   1825   IN UINT8                  NextHeader,
   1826   IN UINT32                 Len
   1827   )
   1828 {
   1829   NET_IP6_PSEUDO_HDR        Hdr;
   1830 
   1831   //
   1832   // Zero the memory to relieve align problems
   1833   //
   1834   ZeroMem (&Hdr, sizeof (Hdr));
   1835 
   1836   IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);
   1837   IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);
   1838 
   1839   Hdr.NextHeader = NextHeader;
   1840   Hdr.Len        = HTONL (Len);
   1841 
   1842   return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
   1843 }
   1844 
   1845 /**
   1846   The function frees the net buffer which allocated by the IP protocol. It releases
   1847   only the net buffer and doesn't call the external free function.
   1848 
   1849   This function should be called after finishing the process of mIpSec->ProcessExt()
   1850   for outbound traffic. The (EFI_IPSEC2_PROTOCOL)->ProcessExt() allocates a new
   1851   buffer for the ESP, so there needs a function to free the old net buffer.
   1852 
   1853   @param[in]  Nbuf       The network buffer to be freed.
   1854 
   1855 **/
   1856 VOID
   1857 NetIpSecNetbufFree (
   1858   NET_BUF   *Nbuf
   1859   )
   1860 {
   1861   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1862   ASSERT (Nbuf->RefCnt > 0);
   1863 
   1864   Nbuf->RefCnt--;
   1865 
   1866   if (Nbuf->RefCnt == 0) {
   1867 
   1868     //
   1869     // Update Vector only when NBuf is to be released. That is,
   1870     // all the sharing of Nbuf increse Vector's RefCnt by one
   1871     //
   1872     NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
   1873     ASSERT (Nbuf->Vector->RefCnt > 0);
   1874 
   1875     Nbuf->Vector->RefCnt--;
   1876 
   1877     if (Nbuf->Vector->RefCnt > 0) {
   1878       return;
   1879     }
   1880 
   1881     //
   1882     // If NET_VECTOR_OWN_FIRST is set, release the first block since it is
   1883     // allocated by us
   1884     //
   1885     if ((Nbuf->Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {
   1886       FreePool (Nbuf->Vector->Block[0].Bulk);
   1887     }
   1888     FreePool (Nbuf->Vector);
   1889     FreePool (Nbuf);
   1890   }
   1891 }
   1892 
   1893