]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c
NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Input.c
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c
deleted file mode 100644 (file)
index 24c5846..0000000
+++ /dev/null
@@ -1,1597 +0,0 @@
-/** @file\r
-  IP4 input process.\r
-\r
-Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
-(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "Ip4Impl.h"\r
-\r
-\r
-/**\r
-  Create an empty assemble entry for the packet identified by\r
-  (Dst, Src, Id, Protocol). The default life for the packet is\r
-  120 seconds.\r
-\r
-  @param[in]  Dst                    The destination address\r
-  @param[in]  Src                    The source address\r
-  @param[in]  Id                     The ID field in IP header\r
-  @param[in]  Protocol               The protocol field in IP header\r
-\r
-  @return NULL if failed to allocate memory for the entry, otherwise\r
-          the point to just created reassemble entry.\r
-\r
-**/\r
-IP4_ASSEMBLE_ENTRY *\r
-Ip4CreateAssembleEntry (\r
-  IN IP4_ADDR               Dst,\r
-  IN IP4_ADDR               Src,\r
-  IN UINT16                 Id,\r
-  IN UINT8                  Protocol\r
-  )\r
-{\r
-\r
-  IP4_ASSEMBLE_ENTRY        *Assemble;\r
-\r
-  Assemble = AllocatePool (sizeof (IP4_ASSEMBLE_ENTRY));\r
-\r
-  if (Assemble == NULL) {\r
-    return NULL;\r
-  }\r
-\r
-  InitializeListHead (&Assemble->Link);\r
-  InitializeListHead (&Assemble->Fragments);\r
-\r
-  Assemble->Dst      = Dst;\r
-  Assemble->Src      = Src;\r
-  Assemble->Id       = Id;\r
-  Assemble->Protocol = Protocol;\r
-  Assemble->TotalLen = 0;\r
-  Assemble->CurLen   = 0;\r
-  Assemble->Head     = NULL;\r
-  Assemble->Info     = NULL;\r
-  Assemble->Life     = IP4_FRAGMENT_LIFE;\r
-\r
-  return Assemble;\r
-}\r
-\r
-\r
-/**\r
-  Release all the fragments of a packet, then free the assemble entry.\r
-\r
-  @param[in]  Assemble               The assemble entry to free\r
-\r
-**/\r
-VOID\r
-Ip4FreeAssembleEntry (\r
-  IN IP4_ASSEMBLE_ENTRY     *Assemble\r
-  )\r
-{\r
-  LIST_ENTRY                *Entry;\r
-  LIST_ENTRY                *Next;\r
-  NET_BUF                   *Fragment;\r
-\r
-  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {\r
-    Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
-\r
-    RemoveEntryList (Entry);\r
-    NetbufFree (Fragment);\r
-  }\r
-\r
-  FreePool (Assemble);\r
-}\r
-\r
-\r
-/**\r
-  Initialize an already allocated assemble table. This is generally\r
-  the assemble table embedded in the IP4 service instance.\r
-\r
-  @param[in, out]  Table                  The assemble table to initialize.\r
-\r
-**/\r
-VOID\r
-Ip4InitAssembleTable (\r
-  IN OUT IP4_ASSEMBLE_TABLE     *Table\r
-  )\r
-{\r
-  UINT32                    Index;\r
-\r
-  for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
-    InitializeListHead (&Table->Bucket[Index]);\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Clean up the assemble table: remove all the fragments\r
-  and assemble entries.\r
-\r
-  @param[in]  Table                  The assemble table to clean up\r
-\r
-**/\r
-VOID\r
-Ip4CleanAssembleTable (\r
-  IN IP4_ASSEMBLE_TABLE     *Table\r
-  )\r
-{\r
-  LIST_ENTRY                *Entry;\r
-  LIST_ENTRY                *Next;\r
-  IP4_ASSEMBLE_ENTRY        *Assemble;\r
-  UINT32                    Index;\r
-\r
-  for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
-    NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {\r
-      Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
-\r
-      RemoveEntryList (Entry);\r
-      Ip4FreeAssembleEntry (Assemble);\r
-    }\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Trim the packet to fit in [Start, End), and update the per\r
-  packet information.\r
-\r
-  @param  Packet                 Packet to trim\r
-  @param  Start                  The sequence of the first byte to fit in\r
-  @param  End                    One beyond the sequence of last byte to fit in.\r
-\r
-**/\r
-VOID\r
-Ip4TrimPacket (\r
-  IN OUT NET_BUF                *Packet,\r
-  IN     INTN                   Start,\r
-  IN     INTN                   End\r
-  )\r
-{\r
-  IP4_CLIP_INFO             *Info;\r
-  INTN                      Len;\r
-\r
-  Info = IP4_GET_CLIP_INFO (Packet);\r
-\r
-  ASSERT (Info->Start + Info->Length == Info->End);\r
-  ASSERT ((Info->Start < End) && (Start < Info->End));\r
-\r
-   if (Info->Start < Start) {\r
-    Len = Start - Info->Start;\r
-\r
-    NetbufTrim (Packet, (UINT32) Len, NET_BUF_HEAD);\r
-    Info->Start   = Start;\r
-    Info->Length -= Len;\r
-  }\r
-\r
-  if (End < Info->End) {\r
-    Len = End - Info->End;\r
-\r
-    NetbufTrim (Packet, (UINT32) Len, NET_BUF_TAIL);\r
-    Info->End     = End;\r
-    Info->Length -= Len;\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Release all the fragments of the packet. This is the callback for\r
-  the assembled packet's OnFree. It will free the assemble entry,\r
-  which in turn will free all the fragments of the packet.\r
-\r
-  @param[in]  Arg                    The assemble entry to free\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4OnFreeFragments (\r
-  IN VOID                   *Arg\r
-  )\r
-{\r
-  Ip4FreeAssembleEntry ((IP4_ASSEMBLE_ENTRY *) Arg);\r
-}\r
-\r
-\r
-/**\r
-  Reassemble the IP fragments. If all the fragments of the packet\r
-  have been received, it will wrap the packet in a net buffer then\r
-  return it to caller. If the packet can't be assembled, NULL is\r
-  return.\r
-\r
-  @param  Table     The assemble table used. New assemble entry will be created\r
-                    if the Packet is from a new chain of fragments.\r
-  @param  Packet    The fragment to assemble. It might be freed if the fragment\r
-                    can't be re-assembled.\r
-\r
-  @return NULL if the packet can't be reassemble. The point to just assembled\r
-          packet if all the fragments of the packet have arrived.\r
-\r
-**/\r
-NET_BUF *\r
-Ip4Reassemble (\r
-  IN OUT IP4_ASSEMBLE_TABLE     *Table,\r
-  IN OUT NET_BUF                *Packet\r
-  )\r
-{\r
-  IP4_HEAD                  *IpHead;\r
-  IP4_CLIP_INFO             *This;\r
-  IP4_CLIP_INFO             *Node;\r
-  IP4_ASSEMBLE_ENTRY        *Assemble;\r
-  LIST_ENTRY                *Head;\r
-  LIST_ENTRY                *Prev;\r
-  LIST_ENTRY                *Cur;\r
-  NET_BUF                   *Fragment;\r
-  NET_BUF                   *NewPacket;\r
-  INTN                      Index;\r
-\r
-  IpHead  = Packet->Ip.Ip4;\r
-  This    = IP4_GET_CLIP_INFO (Packet);\r
-\r
-  ASSERT (IpHead != NULL);\r
-\r
-  //\r
-  // First: find the related assemble entry\r
-  //\r
-  Assemble  = NULL;\r
-  Index     = IP4_ASSEMBLE_HASH (IpHead->Dst, IpHead->Src, IpHead->Id, IpHead->Protocol);\r
-\r
-  NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {\r
-    Assemble = NET_LIST_USER_STRUCT (Cur, IP4_ASSEMBLE_ENTRY, Link);\r
-\r
-    if ((Assemble->Dst == IpHead->Dst) && (Assemble->Src == IpHead->Src) &&\r
-        (Assemble->Id == IpHead->Id)   && (Assemble->Protocol == IpHead->Protocol)) {\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Create a new assemble entry if no assemble entry is related to this packet\r
-  //\r
-  if (Cur == &Table->Bucket[Index]) {\r
-    Assemble = Ip4CreateAssembleEntry (\r
-                 IpHead->Dst,\r
-                 IpHead->Src,\r
-                 IpHead->Id,\r
-                 IpHead->Protocol\r
-                 );\r
-\r
-    if (Assemble == NULL) {\r
-      goto DROP;\r
-    }\r
-\r
-    InsertHeadList (&Table->Bucket[Index], &Assemble->Link);\r
-  }\r
-  //\r
-  // Assemble shouldn't be NULL here\r
-  //\r
-  ASSERT (Assemble != NULL);\r
-\r
-  //\r
-  // Find the point to insert the packet: before the first\r
-  // fragment with THIS.Start < CUR.Start. the previous one\r
-  // has PREV.Start <= THIS.Start < CUR.Start.\r
-  //\r
-  Head = &Assemble->Fragments;\r
-\r
-  NET_LIST_FOR_EACH (Cur, Head) {\r
-    Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
-\r
-    if (This->Start < IP4_GET_CLIP_INFO (Fragment)->Start) {\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check whether the current fragment overlaps with the previous one.\r
-  // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to\r
-  // check whether THIS.Start < PREV.End for overlap. If two fragments\r
-  // overlaps, trim the overlapped part off THIS fragment.\r
-  //\r
-  if ((Prev = Cur->BackLink) != Head) {\r
-    Fragment  = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
-    Node      = IP4_GET_CLIP_INFO (Fragment);\r
-\r
-    if (This->Start < Node->End) {\r
-      if (This->End <= Node->End) {\r
-        NetbufFree (Packet);\r
-        return NULL;\r
-      }\r
-\r
-      Ip4TrimPacket (Packet, Node->End, This->End);\r
-    }\r
-  }\r
-\r
-  //\r
-  // Insert the fragment into the packet. The fragment may be removed\r
-  // from the list by the following checks.\r
-  //\r
-  NetListInsertBefore (Cur, &Packet->List);\r
-\r
-  //\r
-  // Check the packets after the insert point. It holds that:\r
-  // THIS.Start <= NODE.Start < NODE.End. The equality holds\r
-  // if PREV and NEXT are continuous. THIS fragment may fill\r
-  // several holes. Remove the completely overlapped fragments\r
-  //\r
-  while (Cur != Head) {\r
-    Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
-    Node     = IP4_GET_CLIP_INFO (Fragment);\r
-\r
-    //\r
-    // Remove fragments completely overlapped by this fragment\r
-    //\r
-    if (Node->End <= This->End) {\r
-      Cur = Cur->ForwardLink;\r
-\r
-      RemoveEntryList (&Fragment->List);\r
-      Assemble->CurLen -= Node->Length;\r
-\r
-      NetbufFree (Fragment);\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // The conditions are: THIS.Start <= NODE.Start, and THIS.End <\r
-    // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.\r
-    // If two fragments start at the same offset, remove THIS fragment\r
-    // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).\r
-    //\r
-    if (Node->Start < This->End) {\r
-      if (This->Start == Node->Start) {\r
-        RemoveEntryList (&Packet->List);\r
-        goto DROP;\r
-      }\r
-\r
-      Ip4TrimPacket (Packet, This->Start, Node->Start);\r
-    }\r
-\r
-    break;\r
-  }\r
-\r
-  //\r
-  // Update the assemble info: increase the current length. If it is\r
-  // the frist fragment, update the packet's IP head and per packet\r
-  // info. If it is the last fragment, update the total length.\r
-  //\r
-  Assemble->CurLen += This->Length;\r
-\r
-  if (This->Start == 0) {\r
-    //\r
-    // Once the first fragment is enqueued, it can't be removed\r
-    // from the fragment list. So, Assemble->Head always point\r
-    // to valid memory area.\r
-    //\r
-    ASSERT (Assemble->Head == NULL);\r
-\r
-    Assemble->Head  = IpHead;\r
-    Assemble->Info  = IP4_GET_CLIP_INFO (Packet);\r
-  }\r
-\r
-  //\r
-  // Don't update the length more than once.\r
-  //\r
-  if (IP4_LAST_FRAGMENT (IpHead->Fragment) && (Assemble->TotalLen == 0)) {\r
-    Assemble->TotalLen = This->End;\r
-  }\r
-\r
-  //\r
-  // Deliver the whole packet if all the fragments received.\r
-  // All fragments received if:\r
-  //  1. received the last one, so, the total length is know\r
-  //  2. received all the data. If the last fragment on the\r
-  //     queue ends at the total length, all data is received.\r
-  //\r
-  if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {\r
-\r
-    RemoveEntryList (&Assemble->Link);\r
-\r
-    //\r
-    // If the packet is properly formated, the last fragment's End\r
-    // equals to the packet's total length. Otherwise, the packet\r
-    // is a fake, drop it now.\r
-    //\r
-    Fragment = NET_LIST_USER_STRUCT (Head->BackLink, NET_BUF, List);\r
-\r
-    if (IP4_GET_CLIP_INFO (Fragment)->End != Assemble->TotalLen) {\r
-      Ip4FreeAssembleEntry (Assemble);\r
-      return NULL;\r
-    }\r
-\r
-    //\r
-    // Wrap the packet in a net buffer then deliver it up\r
-    //\r
-    NewPacket = NetbufFromBufList (\r
-                  &Assemble->Fragments,\r
-                  0,\r
-                  0,\r
-                  Ip4OnFreeFragments,\r
-                  Assemble\r
-                  );\r
-\r
-    if (NewPacket == NULL) {\r
-      Ip4FreeAssembleEntry (Assemble);\r
-      return NULL;\r
-    }\r
-\r
-    NewPacket->Ip.Ip4 = Assemble->Head;\r
-\r
-    ASSERT (Assemble->Info != NULL);\r
-\r
-    CopyMem (\r
-      IP4_GET_CLIP_INFO (NewPacket),\r
-      Assemble->Info,\r
-      sizeof (*IP4_GET_CLIP_INFO (NewPacket))\r
-      );\r
-\r
-    return NewPacket;\r
-  }\r
-\r
-  return NULL;\r
-\r
-DROP:\r
-  NetbufFree (Packet);\r
-  return NULL;\r
-}\r
-\r
-/**\r
-  The callback function for the net buffer which wraps the packet processed by\r
-  IPsec. It releases the wrap packet and also signals IPsec to free the resources.\r
-\r
-  @param[in]  Arg       The wrap context\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4IpSecFree (\r
-  IN VOID                   *Arg\r
-  )\r
-{\r
-  IP4_IPSEC_WRAP            *Wrap;\r
-\r
-  Wrap = (IP4_IPSEC_WRAP *) Arg;\r
-\r
-  if (Wrap->IpSecRecycleSignal != NULL) {\r
-    gBS->SignalEvent (Wrap->IpSecRecycleSignal);\r
-  }\r
-\r
-  NetbufFree (Wrap->Packet);\r
-\r
-  FreePool (Wrap);\r
-\r
-  return;\r
-}\r
-\r
-/**\r
-  The work function to locate IPsec protocol to process the inbound or\r
-  outbound IP packets. The process routine handls the packet with following\r
-  actions: bypass the packet, discard the packet, or protect the packet.\r
-\r
-  @param[in]       IpSb          The IP4 service instance.\r
-  @param[in, out]  Head          The The caller supplied IP4 header.\r
-  @param[in, out]  Netbuf        The IP4 packet to be processed by IPsec.\r
-  @param[in, out]  Options       The caller supplied options.\r
-  @param[in, out]  OptionsLen    The length of the option.\r
-  @param[in]       Direction     The directionality in an SPD entry,\r
-                                 EfiIPsecInBound or EfiIPsecOutBound.\r
-  @param[in]       Context       The token's wrap.\r
-\r
-  @retval EFI_SUCCESS            The IPsec protocol is not available or disabled.\r
-  @retval EFI_SUCCESS            The packet was bypassed and all buffers remain the same.\r
-  @retval EFI_SUCCESS            The packet was protected.\r
-  @retval EFI_ACCESS_DENIED      The packet was discarded.\r
-  @retval EFI_OUT_OF_RESOURCES   There is no suffcient resource to complete the operation.\r
-  @retval EFI_BUFFER_TOO_SMALL   The number of non-empty block is bigger than the\r
-                                 number of input data blocks when build a fragment table.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4IpSecProcessPacket (\r
-  IN     IP4_SERVICE            *IpSb,\r
-  IN OUT IP4_HEAD               **Head,\r
-  IN OUT NET_BUF                **Netbuf,\r
-  IN OUT UINT8                  **Options,\r
-  IN OUT UINT32                 *OptionsLen,\r
-  IN     EFI_IPSEC_TRAFFIC_DIR  Direction,\r
-  IN     VOID                   *Context\r
-  )\r
-{\r
-  NET_FRAGMENT              *FragmentTable;\r
-  NET_FRAGMENT              *OriginalFragmentTable;\r
-  UINT32                    FragmentCount;\r
-  UINT32                    OriginalFragmentCount;\r
-  EFI_EVENT                 RecycleEvent;\r
-  NET_BUF                   *Packet;\r
-  IP4_TXTOKEN_WRAP          *TxWrap;\r
-  IP4_IPSEC_WRAP            *IpSecWrap;\r
-  EFI_STATUS                Status;\r
-  IP4_HEAD                  ZeroHead;\r
-\r
-  Status        = EFI_SUCCESS;\r
-\r
-  if (!mIpSec2Installed) {\r
-    goto ON_EXIT;\r
-  }\r
-  ASSERT (mIpSec != NULL);\r
-\r
-  Packet        = *Netbuf;\r
-  RecycleEvent  = NULL;\r
-  IpSecWrap     = NULL;\r
-  FragmentTable = NULL;\r
-  TxWrap        = (IP4_TXTOKEN_WRAP *) Context;\r
-  FragmentCount = Packet->BlockOpNum;\r
-\r
-  ZeroMem (&ZeroHead, sizeof (IP4_HEAD));\r
-\r
-  //\r
-  // Check whether the IPsec enable variable is set.\r
-  //\r
-  if (mIpSec->DisabledFlag) {\r
-    //\r
-    // If IPsec is disabled, restore the original MTU\r
-    //\r
-    IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;\r
-    goto ON_EXIT;\r
-  } else {\r
-    //\r
-    // If IPsec is enabled, use the MTU which reduce the IPsec header length.\r
-    //\r
-    IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP4_MAX_IPSEC_HEADLEN;\r
-  }\r
-\r
-  //\r
-  // Rebuild fragment table from netbuf to ease IPsec process.\r
-  //\r
-  FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));\r
-\r
-  if (FragmentTable == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);\r
-\r
-  //\r
-  // Record the original FragmentTable and count.\r
-  //\r
-  OriginalFragmentTable = FragmentTable;\r
-  OriginalFragmentCount = FragmentCount;\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (FragmentTable);\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  //\r
-  // Convert host byte order to network byte order\r
-  //\r
-  Ip4NtohHead (*Head);\r
-\r
-  Status = mIpSec->ProcessExt (\r
-                     mIpSec,\r
-                     IpSb->Controller,\r
-                     IP_VERSION_4,\r
-                     (VOID *) (*Head),\r
-                     &(*Head)->Protocol,\r
-                     (VOID **) Options,\r
-                     OptionsLen,\r
-                     (EFI_IPSEC_FRAGMENT_DATA **) (&FragmentTable),\r
-                     &FragmentCount,\r
-                     Direction,\r
-                     &RecycleEvent\r
-                     );\r
-  //\r
-  // Convert back to host byte order\r
-  //\r
-  Ip4NtohHead (*Head);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (OriginalFragmentTable);\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  if (OriginalFragmentTable == FragmentTable && OriginalFragmentCount == FragmentCount) {\r
-    //\r
-    // For ByPass Packet\r
-    //\r
-    FreePool (FragmentTable);\r
-    goto ON_EXIT;\r
-  } else {\r
-    //\r
-    // Free the FragmentTable which allocated before calling the IPsec.\r
-    //\r
-    FreePool (OriginalFragmentTable);\r
-  }\r
-\r
-  if (Direction == EfiIPsecOutBound && TxWrap != NULL) {\r
-\r
-    TxWrap->IpSecRecycleSignal = RecycleEvent;\r
-    TxWrap->Packet             = NetbufFromExt (\r
-                                   FragmentTable,\r
-                                   FragmentCount,\r
-                                   IP4_MAX_HEADLEN,\r
-                                   0,\r
-                                   Ip4FreeTxToken,\r
-                                   TxWrap\r
-                                   );\r
-    if (TxWrap->Packet == NULL) {\r
-      //\r
-      // Recover the TxWrap->Packet, if meet a error, and the caller will free\r
-      // the TxWrap.\r
-      //\r
-      TxWrap->Packet = *Netbuf;\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    //\r
-    // Free orginal Netbuf.\r
-    //\r
-    NetIpSecNetbufFree (*Netbuf);\r
-    *Netbuf = TxWrap->Packet;\r
-\r
-  } else {\r
-\r
-    IpSecWrap = AllocateZeroPool (sizeof (IP4_IPSEC_WRAP));\r
-\r
-    if (IpSecWrap == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      gBS->SignalEvent (RecycleEvent);\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    IpSecWrap->IpSecRecycleSignal = RecycleEvent;\r
-    IpSecWrap->Packet             = Packet;\r
-    Packet                        = NetbufFromExt (\r
-                                      FragmentTable,\r
-                                      FragmentCount,\r
-                                      IP4_MAX_HEADLEN,\r
-                                      0,\r
-                                      Ip4IpSecFree,\r
-                                      IpSecWrap\r
-                                      );\r
-\r
-    if (Packet == NULL) {\r
-      Packet = IpSecWrap->Packet;\r
-      gBS->SignalEvent (RecycleEvent);\r
-      FreePool (IpSecWrap);\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    if (Direction == EfiIPsecInBound && 0 != CompareMem (*Head, &ZeroHead, sizeof (IP4_HEAD))) {\r
-      Ip4PrependHead (Packet, *Head, *Options, *OptionsLen);\r
-      Ip4NtohHead (Packet->Ip.Ip4);\r
-      NetbufTrim (Packet, ((*Head)->HeadLen << 2), TRUE);\r
-\r
-      CopyMem (\r
-        IP4_GET_CLIP_INFO (Packet),\r
-        IP4_GET_CLIP_INFO (IpSecWrap->Packet),\r
-        sizeof (IP4_CLIP_INFO)\r
-        );\r
-    }\r
-    *Netbuf = Packet;\r
-  }\r
-\r
-ON_EXIT:\r
-  return Status;\r
-}\r
-\r
-/**\r
-  Pre-process the IPv4 packet. First validates the IPv4 packet, and\r
-  then reassembles packet if it is necessary.\r
-\r
-  @param[in]       IpSb            Pointer to IP4_SERVICE.\r
-  @param[in, out]  Packet          Pointer to the Packet to be processed.\r
-  @param[in]       Head            Pointer to the IP4_HEAD.\r
-  @param[in]       Option          Pointer to a buffer which contains the IPv4 option.\r
-  @param[in]       OptionLen       The length of Option in bytes.\r
-  @param[in]       Flag            The link layer flag for the packet received, such\r
-                                   as multicast.\r
-\r
-  @retval     EFI_SEUCCESS               The recieved packet is in well form.\r
-  @retval     EFI_INVAILD_PARAMETER      The recieved packet is malformed.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4PreProcessPacket (\r
-  IN     IP4_SERVICE    *IpSb,\r
-  IN OUT NET_BUF        **Packet,\r
-  IN     IP4_HEAD       *Head,\r
-  IN     UINT8          *Option,\r
-  IN     UINT32         OptionLen,\r
-  IN     UINT32         Flag\r
-  )\r
-{\r
-  IP4_CLIP_INFO             *Info;\r
-  UINT32                    HeadLen;\r
-  UINT32                    TotalLen;\r
-  UINT16                    Checksum;\r
-\r
-  //\r
-  // Check if the IP4 header is correctly formatted.\r
-  //\r
-  if ((*Packet)->TotalSize < IP4_MIN_HEADLEN) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  HeadLen  = (Head->HeadLen << 2);\r
-  TotalLen = NTOHS (Head->TotalLen);\r
-\r
-  //\r
-  // Mnp may deliver frame trailer sequence up, trim it off.\r
-  //\r
-  if (TotalLen < (*Packet)->TotalSize) {\r
-    NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);\r
-  }\r
-\r
-  if ((Head->Ver != 4) || (HeadLen < IP4_MIN_HEADLEN) ||\r
-      (TotalLen < HeadLen) || (TotalLen != (*Packet)->TotalSize)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Some OS may send IP packets without checksum.\r
-  //\r
-  Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Head, HeadLen));\r
-\r
-  if ((Head->Checksum != 0) && (Checksum != 0)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Convert the IP header to host byte order, then get the per packet info.\r
-  //\r
-  (*Packet)->Ip.Ip4  = Ip4NtohHead (Head);\r
-\r
-  Info            = IP4_GET_CLIP_INFO (*Packet);\r
-  Info->LinkFlag  = Flag;\r
-  Info->CastType  = Ip4GetHostCast (IpSb, Head->Dst, Head->Src);\r
-  Info->Start     = (Head->Fragment & IP4_HEAD_OFFSET_MASK) << 3;\r
-  Info->Length    = Head->TotalLen - HeadLen;\r
-  Info->End       = Info->Start + Info->Length;\r
-  Info->Status    = EFI_SUCCESS;\r
-\r
-  //\r
-  // The packet is destinated to us if the CastType is non-zero.\r
-  //\r
-  if ((Info->CastType == 0) || (Info->End > IP4_MAX_PACKET_SIZE)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Validate the options. Don't call the Ip4OptionIsValid if\r
-  // there is no option to save some CPU process.\r
-  //\r
-\r
-  if ((OptionLen > 0) && !Ip4OptionIsValid (Option, OptionLen, TRUE)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Trim the head off, after this point, the packet is headless,\r
-  // and Packet->TotalLen == Info->Length.\r
-  //\r
-  NetbufTrim (*Packet, HeadLen, TRUE);\r
-\r
-  //\r
-  // Reassemble the packet if this is a fragment. The packet is a\r
-  // fragment if its head has MF (more fragment) set, or it starts\r
-  // at non-zero byte.\r
-  //\r
-  if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) || (Info->Start != 0)) {\r
-    //\r
-    // Drop the fragment if DF is set but it is fragmented. Gateway\r
-    // need to send a type 4 destination unreache ICMP message here.\r
-    //\r
-    if ((Head->Fragment & IP4_HEAD_DF_MASK) != 0) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    //\r
-    // The length of all but the last fragments is in the unit of 8 bytes.\r
-    //\r
-    if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) && (Info->Length % 8 != 0)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    *Packet = Ip4Reassemble (&IpSb->Assemble, *Packet);\r
-\r
-    //\r
-    // Packet assembly isn't complete, start receive more packet.\r
-    //\r
-    if (*Packet == NULL) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  The IP4 input routine. It is called by the IP4_INTERFACE when a\r
-  IP4 fragment is received from MNP.\r
-\r
-  @param[in]  Ip4Instance        The IP4 child that request the receive, most like\r
-                                 it is NULL.\r
-  @param[in]  Packet             The IP4 packet received.\r
-  @param[in]  IoStatus           The return status of receive request.\r
-  @param[in]  Flag               The link layer flag for the packet received, such\r
-                                 as multicast.\r
-  @param[in]  Context            The IP4 service instance that own the MNP.\r
-\r
-**/\r
-VOID\r
-Ip4AccpetFrame (\r
-  IN IP4_PROTOCOL           *Ip4Instance,\r
-  IN NET_BUF                *Packet,\r
-  IN EFI_STATUS             IoStatus,\r
-  IN UINT32                 Flag,\r
-  IN VOID                   *Context\r
-  )\r
-{\r
-  IP4_SERVICE               *IpSb;\r
-  IP4_HEAD                  *Head;\r
-  EFI_STATUS                Status;\r
-  IP4_HEAD                  ZeroHead;\r
-  UINT8                     *Option;\r
-  UINT32                    OptionLen;\r
-\r
-  IpSb   = (IP4_SERVICE *) Context;\r
-  Option = NULL;\r
-\r
-  if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTROY)) {\r
-    goto DROP;\r
-  }\r
-\r
-  Head      = (IP4_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
-  ASSERT (Head != NULL);\r
-  OptionLen = (Head->HeadLen << 2) - IP4_MIN_HEADLEN;\r
-  if (OptionLen > 0) {\r
-    Option = (UINT8 *) (Head + 1);\r
-  }\r
-\r
-  //\r
-  // Validate packet format and reassemble packet if it is necessary.\r
-  //\r
-  Status = Ip4PreProcessPacket (\r
-             IpSb,\r
-             &Packet,\r
-             Head,\r
-             Option,\r
-             OptionLen,\r
-             Flag\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto RESTART;\r
-  }\r
-\r
-  //\r
-  // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,\r
-  // and no need consider any other ahead ext headers.\r
-  //\r
-  Status = Ip4IpSecProcessPacket (\r
-             IpSb,\r
-             &Head,\r
-             &Packet,\r
-             &Option,\r
-             &OptionLen,\r
-             EfiIPsecInBound,\r
-             NULL\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto RESTART;\r
-  }\r
-\r
-  //\r
-  // If the packet is protected by tunnel mode, parse the inner Ip Packet.\r
-  //\r
-  ZeroMem (&ZeroHead, sizeof (IP4_HEAD));\r
-  if (0 == CompareMem (Head, &ZeroHead, sizeof (IP4_HEAD))) {\r
-  // Packet may have been changed. Head, HeadLen, TotalLen, and\r
-  // info must be reloaded bofore use. The ownership of the packet\r
-  // is transfered to the packet process logic.\r
-  //\r
-    Head = (IP4_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
-    ASSERT (Head != NULL);\r
-    Status = Ip4PreProcessPacket (\r
-               IpSb,\r
-               &Packet,\r
-               Head,\r
-               Option,\r
-               OptionLen,\r
-               Flag\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      goto RESTART;\r
-    }\r
-  }\r
-\r
-  ASSERT (Packet != NULL);\r
-  Head  = Packet->Ip.Ip4;\r
-  IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;\r
-\r
-  switch (Head->Protocol) {\r
-  case EFI_IP_PROTO_ICMP:\r
-    Ip4IcmpHandle (IpSb, Head, Packet);\r
-    break;\r
-\r
-  case IP4_PROTO_IGMP:\r
-    Ip4IgmpHandle (IpSb, Head, Packet);\r
-    break;\r
-\r
-  default:\r
-    Ip4Demultiplex (IpSb, Head, Packet, Option, OptionLen);\r
-  }\r
-\r
-  Packet = NULL;\r
-\r
-  //\r
-  // Dispatch the DPCs queued by the NotifyFunction of the rx token's events\r
-  // which are signaled with received data.\r
-  //\r
-  DispatchDpc ();\r
-\r
-RESTART:\r
-  Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
-\r
-DROP:\r
-  if (Packet != NULL) {\r
-    NetbufFree (Packet);\r
-  }\r
-\r
-  return ;\r
-}\r
-\r
-\r
-/**\r
-  Check whether this IP child accepts the packet.\r
-\r
-  @param[in]  IpInstance             The IP child to check\r
-  @param[in]  Head                   The IP header of the packet\r
-  @param[in]  Packet                 The data of the packet\r
-\r
-  @retval TRUE   If the child wants to receive the packet.\r
-  @retval FALSE  Otherwise.\r
-\r
-**/\r
-BOOLEAN\r
-Ip4InstanceFrameAcceptable (\r
-  IN IP4_PROTOCOL           *IpInstance,\r
-  IN IP4_HEAD               *Head,\r
-  IN NET_BUF                *Packet\r
-  )\r
-{\r
-  IP4_ICMP_ERROR_HEAD       Icmp;\r
-  EFI_IP4_CONFIG_DATA       *Config;\r
-  IP4_CLIP_INFO             *Info;\r
-  UINT16                    Proto;\r
-  UINT32                    Index;\r
-\r
-  Config = &IpInstance->ConfigData;\r
-\r
-  //\r
-  // Dirty trick for the Tiano UEFI network stack implmentation. If\r
-  // ReceiveTimeout == -1, the receive of the packet for this instance\r
-  // is disabled. The UEFI spec don't have such capability. We add\r
-  // this to improve the performance because IP will make a copy of\r
-  // the received packet for each accepting instance. Some IP instances\r
-  // used by UDP/TCP only send packets, they don't wants to receive.\r
-  //\r
-  if (Config->ReceiveTimeout == (UINT32)(-1)) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (Config->AcceptPromiscuous) {\r
-    return TRUE;\r
-  }\r
-\r
-  //\r
-  // Use protocol from the IP header embedded in the ICMP error\r
-  // message to filter, instead of ICMP itself. ICMP handle will\r
-  // call Ip4Demultiplex to deliver ICMP errors.\r
-  //\r
-  Proto = Head->Protocol;\r
-\r
-  if ((Proto == EFI_IP_PROTO_ICMP) && (!Config->AcceptAnyProtocol) && (Proto != Config->DefaultProtocol)) {\r
-    NetbufCopy (Packet, 0, sizeof (Icmp.Head), (UINT8 *) &Icmp.Head);\r
-\r
-    if (mIcmpClass[Icmp.Head.Type].IcmpClass == ICMP_ERROR_MESSAGE) {\r
-      if (!Config->AcceptIcmpErrors) {\r
-        return FALSE;\r
-      }\r
-\r
-      NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
-      Proto = Icmp.IpHead.Protocol;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Match the protocol\r
-  //\r
-  if (!Config->AcceptAnyProtocol && (Proto != Config->DefaultProtocol)) {\r
-    return FALSE;\r
-  }\r
-\r
-  //\r
-  // Check for broadcast, the caller has computed the packet's\r
-  // cast type for this child's interface.\r
-  //\r
-  Info = IP4_GET_CLIP_INFO (Packet);\r
-\r
-  if (IP4_IS_BROADCAST (Info->CastType)) {\r
-    return Config->AcceptBroadcast;\r
-  }\r
-\r
-  //\r
-  // If it is a multicast packet, check whether we are in the group.\r
-  //\r
-  if (Info->CastType == IP4_MULTICAST) {\r
-    //\r
-    // Receive the multicast if the instance wants to receive all packets.\r
-    //\r
-    if (!IpInstance->ConfigData.UseDefaultAddress && (IpInstance->Interface->Ip == 0)) {\r
-      return TRUE;\r
-    }\r
-\r
-    for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
-      if (IpInstance->Groups[Index] == HTONL (Head->Dst)) {\r
-        break;\r
-      }\r
-    }\r
-\r
-    return (BOOLEAN)(Index < IpInstance->GroupCount);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-\r
-/**\r
-  Enqueue a shared copy of the packet to the IP4 child if the\r
-  packet is acceptable to it. Here the data of the packet is\r
-  shared, but the net buffer isn't.\r
-\r
-  @param[in]  IpInstance             The IP4 child to enqueue the packet to\r
-  @param[in]  Head                   The IP header of the received packet\r
-  @param[in]  Packet                 The data of the received packet\r
-\r
-  @retval EFI_NOT_STARTED        The IP child hasn't been configured.\r
-  @retval EFI_INVALID_PARAMETER  The child doesn't want to receive the packet\r
-  @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resource\r
-  @retval EFI_SUCCESS            A shared copy the packet is enqueued to the child.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4InstanceEnquePacket (\r
-  IN IP4_PROTOCOL           *IpInstance,\r
-  IN IP4_HEAD               *Head,\r
-  IN NET_BUF                *Packet\r
-  )\r
-{\r
-  IP4_CLIP_INFO             *Info;\r
-  NET_BUF                   *Clone;\r
-\r
-  //\r
-  // Check whether the packet is acceptable to this instance.\r
-  //\r
-  if (IpInstance->State != IP4_STATE_CONFIGED) {\r
-    return EFI_NOT_STARTED;\r
-  }\r
-\r
-  if (!Ip4InstanceFrameAcceptable (IpInstance, Head, Packet)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Enque a shared copy of the packet.\r
-  //\r
-  Clone = NetbufClone (Packet);\r
-\r
-  if (Clone == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  //\r
-  // Set the receive time out for the assembled packet. If it expires,\r
-  // packet will be removed from the queue.\r
-  //\r
-  Info        = IP4_GET_CLIP_INFO (Clone);\r
-  Info->Life  = IP4_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);\r
-\r
-  InsertTailList (&IpInstance->Received, &Clone->List);\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-  The signal handle of IP4's recycle event. It is called back\r
-  when the upper layer release the packet.\r
-\r
-  @param  Event              The IP4's recycle event.\r
-  @param  Context            The context of the handle, which is a\r
-                             IP4_RXDATA_WRAP\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4OnRecyclePacket (\r
-  IN EFI_EVENT              Event,\r
-  IN VOID                   *Context\r
-  )\r
-{\r
-  IP4_RXDATA_WRAP           *Wrap;\r
-\r
-  Wrap = (IP4_RXDATA_WRAP *) Context;\r
-\r
-  EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);\r
-  RemoveEntryList (&Wrap->Link);\r
-  EfiReleaseLock (&Wrap->IpInstance->RecycleLock);\r
-\r
-  ASSERT (!NET_BUF_SHARED (Wrap->Packet));\r
-  NetbufFree (Wrap->Packet);\r
-\r
-  gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
-  FreePool (Wrap);\r
-}\r
-\r
-\r
-/**\r
-  Wrap the received packet to a IP4_RXDATA_WRAP, which will be\r
-  delivered to the upper layer. Each IP4 child that accepts the\r
-  packet will get a not-shared copy of the packet which is wrapped\r
-  in the IP4_RXDATA_WRAP. The IP4_RXDATA_WRAP->RxData is passed\r
-  to the upper layer. Upper layer will signal the recycle event in\r
-  it when it is done with the packet.\r
-\r
-  @param[in]  IpInstance    The IP4 child to receive the packet.\r
-  @param[in]  Packet        The packet to deliver up.\r
-\r
-  @retval Wrap              if warp the packet succeed.\r
-  @retval NULL              failed to wrap the packet .\r
-\r
-**/\r
-IP4_RXDATA_WRAP *\r
-Ip4WrapRxData (\r
-  IN IP4_PROTOCOL           *IpInstance,\r
-  IN NET_BUF                *Packet\r
-  )\r
-{\r
-  IP4_RXDATA_WRAP           *Wrap;\r
-  EFI_IP4_RECEIVE_DATA      *RxData;\r
-  EFI_STATUS                Status;\r
-  BOOLEAN                   RawData;\r
-\r
-  Wrap = AllocatePool (IP4_RXDATA_WRAP_SIZE (Packet->BlockOpNum));\r
-\r
-  if (Wrap == NULL) {\r
-    return NULL;\r
-  }\r
-\r
-  InitializeListHead (&Wrap->Link);\r
-\r
-  Wrap->IpInstance  = IpInstance;\r
-  Wrap->Packet      = Packet;\r
-  RxData            = &Wrap->RxData;\r
-\r
-  ZeroMem (RxData, sizeof (EFI_IP4_RECEIVE_DATA));\r
-\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  Ip4OnRecyclePacket,\r
-                  Wrap,\r
-                  &RxData->RecycleSignal\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (Wrap);\r
-    return NULL;\r
-  }\r
-\r
-  ASSERT (Packet->Ip.Ip4 != NULL);\r
-\r
-  ASSERT (IpInstance != NULL);\r
-  RawData = IpInstance->ConfigData.RawData;\r
-\r
-  //\r
-  // The application expects a network byte order header.\r
-  //\r
-  if (!RawData) {\r
-    RxData->HeaderLength  = (Packet->Ip.Ip4->HeadLen << 2);\r
-    RxData->Header        = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip.Ip4);\r
-    RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;\r
-    RxData->Options       = NULL;\r
-\r
-    if (RxData->OptionsLength != 0) {\r
-      RxData->Options = (VOID *) (RxData->Header + 1);\r
-    }\r
-  }\r
-\r
-  RxData->DataLength  = Packet->TotalSize;\r
-\r
-  //\r
-  // Build the fragment table to be delivered up.\r
-  //\r
-  RxData->FragmentCount = Packet->BlockOpNum;\r
-  NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);\r
-\r
-  return Wrap;\r
-}\r
-\r
-\r
-/**\r
-  Deliver the received packets to upper layer if there are both received\r
-  requests and enqueued packets. If the enqueued packet is shared, it will\r
-  duplicate it to a non-shared packet, release the shared packet, then\r
-  deliver the non-shared packet up.\r
-\r
-  @param[in]  IpInstance         The IP child to deliver the packet up.\r
-\r
-  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources to deliver the\r
-                                 packets.\r
-  @retval EFI_SUCCESS            All the enqueued packets that can be delivered\r
-                                 are delivered up.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4InstanceDeliverPacket (\r
-  IN IP4_PROTOCOL           *IpInstance\r
-  )\r
-{\r
-  EFI_IP4_COMPLETION_TOKEN  *Token;\r
-  IP4_RXDATA_WRAP           *Wrap;\r
-  NET_BUF                   *Packet;\r
-  NET_BUF                   *Dup;\r
-  UINT8                     *Head;\r
-  UINT32                    HeadLen;\r
-\r
-  //\r
-  // Deliver a packet if there are both a packet and a receive token.\r
-  //\r
-  while (!IsListEmpty (&IpInstance->Received) &&\r
-         !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
-\r
-    Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);\r
-\r
-    if (!NET_BUF_SHARED (Packet)) {\r
-      //\r
-      // If this is the only instance that wants the packet, wrap it up.\r
-      //\r
-      Wrap = Ip4WrapRxData (IpInstance, Packet);\r
-\r
-      if (Wrap == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-\r
-      RemoveEntryList (&Packet->List);\r
-\r
-    } else {\r
-      //\r
-      // Create a duplicated packet if this packet is shared\r
-      //\r
-      if (IpInstance->ConfigData.RawData) {\r
-        HeadLen = 0;\r
-      } else {\r
-        HeadLen = IP4_MAX_HEADLEN;\r
-      }\r
-\r
-      Dup = NetbufDuplicate (Packet, NULL, HeadLen);\r
-\r
-      if (Dup == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-\r
-      if (!IpInstance->ConfigData.RawData) {\r
-        //\r
-        // Copy the IP head over. The packet to deliver up is\r
-        // headless. Trim the head off after copy. The IP head\r
-        // may be not continuous before the data.\r
-        //\r
-        Head = NetbufAllocSpace (Dup, IP4_MAX_HEADLEN, NET_BUF_HEAD);\r
-        ASSERT (Head != NULL);\r
-\r
-        Dup->Ip.Ip4 = (IP4_HEAD *) Head;\r
-\r
-        CopyMem (Head, Packet->Ip.Ip4, Packet->Ip.Ip4->HeadLen << 2);\r
-        NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);\r
-      }\r
-\r
-      Wrap = Ip4WrapRxData (IpInstance, Dup);\r
-\r
-      if (Wrap == NULL) {\r
-        NetbufFree (Dup);\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-\r
-      RemoveEntryList (&Packet->List);\r
-      NetbufFree (Packet);\r
-\r
-      Packet = Dup;\r
-    }\r
-\r
-    //\r
-    // Insert it into the delivered packet, then get a user's\r
-    // receive token, pass the wrapped packet up.\r
-    //\r
-    EfiAcquireLockOrFail (&IpInstance->RecycleLock);\r
-    InsertHeadList (&IpInstance->Delivered, &Wrap->Link);\r
-    EfiReleaseLock (&IpInstance->RecycleLock);\r
-\r
-    Token                = NetMapRemoveHead (&IpInstance->RxTokens, NULL);\r
-    Token->Status        = IP4_GET_CLIP_INFO (Packet)->Status;\r
-    Token->Packet.RxData = &Wrap->RxData;\r
-\r
-    gBS->SignalEvent (Token->Event);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-  Enqueue a received packet to all the IP children that share\r
-  the same interface.\r
-\r
-  @param[in]  IpSb               The IP4 service instance that receive the packet.\r
-  @param[in]  Head               The header of the received packet.\r
-  @param[in]  Packet             The data of the received packet.\r
-  @param[in]  Option             Point to the IP4 packet header options.\r
-  @param[in]  OptionLen          Length of the IP4 packet header options.\r
-  @param[in]  IpIf               The interface to enqueue the packet to.\r
-\r
-  @return The number of the IP4 children that accepts the packet\r
-\r
-**/\r
-INTN\r
-Ip4InterfaceEnquePacket (\r
-  IN IP4_SERVICE            *IpSb,\r
-  IN IP4_HEAD               *Head,\r
-  IN NET_BUF                *Packet,\r
-  IN UINT8                  *Option,\r
-  IN UINT32                 OptionLen,\r
-  IN IP4_INTERFACE          *IpIf\r
-  )\r
-{\r
-  IP4_PROTOCOL              *IpInstance;\r
-  IP4_CLIP_INFO             *Info;\r
-  LIST_ENTRY                *Entry;\r
-  INTN                      Enqueued;\r
-  INTN                      LocalType;\r
-  INTN                      SavedType;\r
-\r
-  //\r
-  // First, check that the packet is acceptable to this interface\r
-  // and find the local cast type for the interface. A packet sent\r
-  // to say 192.168.1.1 should NOT be delliever to 10.0.0.1 unless\r
-  // promiscuous receiving.\r
-  //\r
-  LocalType = 0;\r
-  Info      = IP4_GET_CLIP_INFO (Packet);\r
-\r
-  if ((Info->CastType == IP4_MULTICAST) || (Info->CastType == IP4_LOCAL_BROADCAST)) {\r
-    //\r
-    // If the CastType is multicast, don't need to filter against\r
-    // the group address here, Ip4InstanceFrameAcceptable will do\r
-    // that later.\r
-    //\r
-    LocalType = Info->CastType;\r
-\r
-  } else {\r
-    //\r
-    // Check the destination againist local IP. If the station\r
-    // address is 0.0.0.0, it means receiving all the IP destined\r
-    // to local non-zero IP. Otherwise, it is necessary to compare\r
-    // the destination to the interface's IP address.\r
-    //\r
-    if (IpIf->Ip == IP4_ALLZERO_ADDRESS) {\r
-      LocalType = IP4_LOCAL_HOST;\r
-\r
-    } else {\r
-      LocalType = Ip4GetNetCast (Head->Dst, IpIf);\r
-\r
-      if ((LocalType == 0) && IpIf->PromiscRecv) {\r
-        LocalType = IP4_PROMISCUOUS;\r
-      }\r
-    }\r
-  }\r
-\r
-  if (LocalType == 0) {\r
-    return 0;\r
-  }\r
-\r
-  //\r
-  // Iterate through the ip instances on the interface, enqueue\r
-  // the packet if filter passed. Save the original cast type,\r
-  // and pass the local cast type to the IP children on the\r
-  // interface. The global cast type will be restored later.\r
-  //\r
-  SavedType       = Info->CastType;\r
-  Info->CastType  = LocalType;\r
-\r
-  Enqueued        = 0;\r
-\r
-  NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
-    IpInstance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
-    NET_CHECK_SIGNATURE (IpInstance, IP4_PROTOCOL_SIGNATURE);\r
-\r
-    //\r
-    // In RawData mode, add IPv4 headers and options back to packet.\r
-    //\r
-    if ((IpInstance->ConfigData.RawData) && (Option != NULL) && (OptionLen != 0)){\r
-      Ip4PrependHead (Packet, Head, Option, OptionLen);\r
-    }\r
-\r
-    if (Ip4InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {\r
-      Enqueued++;\r
-    }\r
-  }\r
-\r
-  Info->CastType = SavedType;\r
-  return Enqueued;\r
-}\r
-\r
-\r
-/**\r
-  Deliver the packet for each IP4 child on the interface.\r
-\r
-  @param[in]  IpSb               The IP4 service instance that received the packet\r
-  @param[in]  IpIf               The IP4 interface to deliver the packet.\r
-\r
-  @retval EFI_SUCCESS            It always returns EFI_SUCCESS now\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4InterfaceDeliverPacket (\r
-  IN IP4_SERVICE            *IpSb,\r
-  IN IP4_INTERFACE          *IpIf\r
-  )\r
-{\r
-  IP4_PROTOCOL              *Ip4Instance;\r
-  LIST_ENTRY                *Entry;\r
-\r
-  NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
-    Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
-    Ip4InstanceDeliverPacket (Ip4Instance);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-  Demultiple the packet. the packet delivery is processed in two\r
-  passes. The first pass will enque a shared copy of the packet\r
-  to each IP4 child that accepts the packet. The second pass will\r
-  deliver a non-shared copy of the packet to each IP4 child that\r
-  has pending receive requests. Data is copied if more than one\r
-  child wants to consume the packet because each IP child needs\r
-  its own copy of the packet to make changes.\r
-\r
-  @param[in]  IpSb               The IP4 service instance that received the packet.\r
-  @param[in]  Head               The header of the received packet.\r
-  @param[in]  Packet             The data of the received packet.\r
-  @param[in]  Option             Point to the IP4 packet header options.\r
-  @param[in]  OptionLen          Length of the IP4 packet header options.\r
-\r
-  @retval EFI_NOT_FOUND          No IP child accepts the packet.\r
-  @retval EFI_SUCCESS            The packet is enqueued or delivered to some IP\r
-                                 children.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4Demultiplex (\r
-  IN IP4_SERVICE            *IpSb,\r
-  IN IP4_HEAD               *Head,\r
-  IN NET_BUF                *Packet,\r
-  IN UINT8                  *Option,\r
-  IN UINT32                 OptionLen\r
-  )\r
-{\r
-  LIST_ENTRY                *Entry;\r
-  IP4_INTERFACE             *IpIf;\r
-  INTN                      Enqueued;\r
-\r
-  //\r
-  // Two pass delivery: first, enque a shared copy of the packet\r
-  // to each instance that accept the packet.\r
-  //\r
-  Enqueued = 0;\r
-\r
-  NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
-    IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
-\r
-    if (IpIf->Configured) {\r
-      Enqueued += Ip4InterfaceEnquePacket (\r
-                    IpSb,\r
-                    Head,\r
-                    Packet,\r
-                    Option,\r
-                    OptionLen,\r
-                    IpIf\r
-                    );\r
-    }\r
-  }\r
-\r
-  //\r
-  // Second: deliver a duplicate of the packet to each instance.\r
-  // Release the local reference first, so that the last instance\r
-  // getting the packet will not copy the data.\r
-  //\r
-  NetbufFree (Packet);\r
-\r
-  if (Enqueued == 0) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
-    IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
-\r
-    if (IpIf->Configured) {\r
-      Ip4InterfaceDeliverPacket (IpSb, IpIf);\r
-    }\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-  Timeout the fragment and enqueued packets.\r
-\r
-  @param[in]  IpSb                   The IP4 service instance to timeout\r
-\r
-**/\r
-VOID\r
-Ip4PacketTimerTicking (\r
-  IN IP4_SERVICE            *IpSb\r
-  )\r
-{\r
-  LIST_ENTRY                *InstanceEntry;\r
-  LIST_ENTRY                *Entry;\r
-  LIST_ENTRY                *Next;\r
-  IP4_PROTOCOL              *IpInstance;\r
-  IP4_ASSEMBLE_ENTRY        *Assemble;\r
-  NET_BUF                   *Packet;\r
-  IP4_CLIP_INFO             *Info;\r
-  UINT32                    Index;\r
-\r
-  //\r
-  // First, time out the fragments. The packet's life is counting down\r
-  // once the first-arrived fragment was received.\r
-  //\r
-  for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
-    NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->Assemble.Bucket[Index]) {\r
-      Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
-\r
-      if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {\r
-        RemoveEntryList (Entry);\r
-        Ip4FreeAssembleEntry (Assemble);\r
-      }\r
-    }\r
-  }\r
-\r
-  NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {\r
-    IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP4_PROTOCOL, Link);\r
-\r
-    //\r
-    // Second, time out the assembled packets enqueued on each IP child.\r
-    //\r
-    NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {\r
-      Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
-      Info   = IP4_GET_CLIP_INFO (Packet);\r
-\r
-      if ((Info->Life > 0) && (--Info->Life == 0)) {\r
-        RemoveEntryList (Entry);\r
-        NetbufFree (Packet);\r
-      }\r
-    }\r
-\r
-    //\r
-    // Third: time out the transmitted packets.\r
-    //\r
-    NetMapIterate (&IpInstance->TxTokens, Ip4SentPacketTicking, NULL);\r
-  }\r
-}\r