]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Input.c
index 9aa426fb2e6664994305048a8025606984bc4e9d..24c5846588031b0e0a43f7d13708973e98a63632 100644 (file)
@@ -1,14 +1,10 @@
 /** @file\r
   IP4 input process.\r
-  \r
-Copyright (c) 2005 - 2007, Intel Corporation.<BR>\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
 \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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
@@ -85,7 +81,7 @@ Ip4FreeAssembleEntry (
     NetbufFree (Fragment);\r
   }\r
 \r
-  gBS->FreePool (Assemble);\r
+  FreePool (Assemble);\r
 }\r
 \r
 \r
@@ -188,6 +184,7 @@ Ip4TrimPacket (
 \r
 **/\r
 VOID\r
+EFIAPI\r
 Ip4OnFreeFragments (\r
   IN VOID                   *Arg\r
   )\r
@@ -228,7 +225,7 @@ Ip4Reassemble (
   NET_BUF                   *NewPacket;\r
   INTN                      Index;\r
 \r
-  IpHead  = Packet->Ip;\r
+  IpHead  = Packet->Ip.Ip4;\r
   This    = IP4_GET_CLIP_INFO (Packet);\r
 \r
   ASSERT (IpHead != NULL);\r
@@ -265,6 +262,10 @@ Ip4Reassemble (
 \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
@@ -287,7 +288,7 @@ Ip4Reassemble (
   // 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->ForwardLink) != Head) {\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
@@ -413,8 +414,16 @@ Ip4Reassemble (
       return NULL;\r
     }\r
 \r
-    NewPacket->Ip = Assemble->Head;\r
-    CopyMem (IP4_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (*IP4_GET_CLIP_INFO (NewPacket)));\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
@@ -425,64 +434,300 @@ DROP:
   return NULL;\r
 }\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
+  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]  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
+  @param[in]  Arg       The wrap context\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
+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_SERVICE               *IpSb;\r
   IP4_CLIP_INFO             *Info;\r
-  IP4_HEAD                  *Head;\r
   UINT32                    HeadLen;\r
-  UINT32                    OptionLen;\r
   UINT32                    TotalLen;\r
   UINT16                    Checksum;\r
 \r
-  IpSb = (IP4_SERVICE *) Context;\r
-\r
-  if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTORY)) {\r
-    goto DROP;\r
-  }\r
-\r
   //\r
-  // Check that the IP4 header is correctly formatted\r
+  // Check if the IP4 header is correctly formatted.\r
   //\r
-  if (Packet->TotalSize < IP4_MIN_HEADLEN) {\r
-    goto RESTART;\r
+  if ((*Packet)->TotalSize < IP4_MIN_HEADLEN) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Head     = (IP4_HEAD *) NetbufGetByte (Packet, 0, NULL);\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
+  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
-    goto RESTART;\r
+      (TotalLen < HeadLen) || (TotalLen != (*Packet)->TotalSize)) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
@@ -491,15 +736,15 @@ Ip4AccpetFrame (
   Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Head, HeadLen));\r
 \r
   if ((Head->Checksum != 0) && (Checksum != 0)) {\r
-    goto RESTART;\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      = Ip4NtohHead (Head);\r
+  (*Packet)->Ip.Ip4  = Ip4NtohHead (Head);\r
 \r
-  Info            = IP4_GET_CLIP_INFO (Packet);\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
@@ -511,66 +756,165 @@ Ip4AccpetFrame (
   // 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
-    goto RESTART;\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
-  OptionLen = HeadLen - IP4_MIN_HEADLEN;\r
 \r
-  if ((OptionLen > 0) && !Ip4OptionIsValid ((UINT8 *) (Head + 1), OptionLen, TRUE)) {\r
-    goto RESTART;\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
+  // Trim the head off, after this point, the packet is headless,\r
   // and Packet->TotalLen == Info->Length.\r
   //\r
-  NetbufTrim (Packet, HeadLen, TRUE);\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) || (Info->Start != 0)) {\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) {\r
-      goto RESTART;\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) && (Info->Length % 8 != 0)) {\r
-      goto RESTART;\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
+    *Packet = Ip4Reassemble (&IpSb->Assemble, *Packet);\r
 \r
     //\r
     // Packet assembly isn't complete, start receive more packet.\r
     //\r
-    if (Packet == NULL) {\r
-      goto RESTART;\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  = Packet->Ip;\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 IP4_PROTO_ICMP:\r
+  case EFI_IP_PROTO_ICMP:\r
     Ip4IcmpHandle (IpSb, Head, Packet);\r
     break;\r
 \r
@@ -579,7 +923,7 @@ Ip4AccpetFrame (
     break;\r
 \r
   default:\r
-    Ip4Demultiplex (IpSb, Head, Packet);\r
+    Ip4Demultiplex (IpSb, Head, Packet, Option, OptionLen);\r
   }\r
 \r
   Packet = NULL;\r
@@ -588,7 +932,7 @@ Ip4AccpetFrame (
   // Dispatch the DPCs queued by the NotifyFunction of the rx token's events\r
   // which are signaled with received data.\r
   //\r
-  NetLibDispatchDpc ();\r
+  DispatchDpc ();\r
 \r
 RESTART:\r
   Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
@@ -647,11 +991,11 @@ Ip4InstanceFrameAcceptable (
   //\r
   // Use protocol from the IP header embedded in the ICMP error\r
   // message to filter, instead of ICMP itself. ICMP handle will\r
-  // can Ip4Demultiplex to deliver ICMP errors.\r
+  // call Ip4Demultiplex to deliver ICMP errors.\r
   //\r
   Proto = Head->Protocol;\r
 \r
-  if (Proto == IP4_PROTO_ICMP) {\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
@@ -790,7 +1134,7 @@ Ip4OnRecyclePacket (
   NetbufFree (Wrap->Packet);\r
 \r
   gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
-  gBS->FreePool (Wrap);\r
+  FreePool (Wrap);\r
 }\r
 \r
 \r
@@ -802,8 +1146,8 @@ Ip4OnRecyclePacket (
   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
+  @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
@@ -818,6 +1162,7 @@ Ip4WrapRxData (
   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
@@ -831,7 +1176,7 @@ Ip4WrapRxData (
   Wrap->Packet      = Packet;\r
   RxData            = &Wrap->RxData;\r
 \r
-  ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));\r
+  ZeroMem (RxData, sizeof (EFI_IP4_RECEIVE_DATA));\r
 \r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
@@ -842,23 +1187,27 @@ Ip4WrapRxData (
                   );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (Wrap);\r
+    FreePool (Wrap);\r
     return NULL;\r
   }\r
 \r
-  ASSERT (Packet->Ip != NULL);\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
-  RxData->HeaderLength  = (Packet->Ip->HeadLen << 2);\r
-  RxData->Header        = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip);\r
-\r
-  RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;\r
-  RxData->Options       = NULL;\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
+    if (RxData->OptionsLength != 0) {\r
+      RxData->Options = (VOID *) (RxData->Header + 1);\r
+    }\r
   }\r
 \r
   RxData->DataLength  = Packet->TotalSize;\r
@@ -897,6 +1246,7 @@ Ip4InstanceDeliverPacket (
   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
@@ -922,22 +1272,32 @@ Ip4InstanceDeliverPacket (
       //\r
       // Create a duplicated packet if this packet is shared\r
       //\r
-      Dup = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);\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
-      //\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
-      Dup->Ip = (IP4_HEAD *) Head;\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
-      CopyMem (Head, Packet->Ip, Packet->Ip->HeadLen << 2);\r
-      NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);\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
@@ -975,10 +1335,12 @@ Ip4InstanceDeliverPacket (
   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]  IpIf                   The interface to enqueue the packet to\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
@@ -988,6 +1350,8 @@ Ip4InterfaceEnquePacket (
   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
@@ -1053,6 +1417,13 @@ Ip4InterfaceEnquePacket (
     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
@@ -1099,11 +1470,13 @@ Ip4InterfaceDeliverPacket (
   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]  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_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
@@ -1112,7 +1485,9 @@ EFI_STATUS
 Ip4Demultiplex (\r
   IN IP4_SERVICE            *IpSb,\r
   IN IP4_HEAD               *Head,\r
-  IN NET_BUF                *Packet\r
+  IN NET_BUF                *Packet,\r
+  IN UINT8                  *Option,\r
+  IN UINT32                 OptionLen\r
   )\r
 {\r
   LIST_ENTRY                *Entry;\r
@@ -1129,7 +1504,14 @@ Ip4Demultiplex (
     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
 \r
     if (IpIf->Configured) {\r
-      Enqueued += Ip4InterfaceEnquePacket (IpSb, Head, Packet, IpIf);\r
+      Enqueued += Ip4InterfaceEnquePacket (\r
+                    IpSb,\r
+                    Head,\r
+                    Packet,\r
+                    Option,\r
+                    OptionLen,\r
+                    IpIf\r
+                    );\r
     }\r
   }\r
 \r