]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
index 2dd6e60bb58496d7e2e85d89f85d7466a95ae10b..d45f0070b3fc87a7b7446c77287426f6a17d799d 100644 (file)
@@ -1,47 +1,30 @@
 /** @file\r
+  IpIo Library.\r
 \r
-Copyright (c) 2005 - 2007, Intel Corporation\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
-\r
-Module Name:\r
-\r
-  IpIo.c\r
-\r
-Abstract:\r
-\r
-  The implementation of the IpIo layer.\r
-\r
-\r
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
-#include <PiDxe.h>\r
+#include <Uefi.h>\r
 \r
 #include <Protocol/Udp4.h>\r
 \r
 #include <Library/IpIoLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-\r
+#include <Library/DpcLib.h>\r
 \r
-#define NET_PROTO_HDR(Buf, Type)  ((Type *) ((Buf)->BlockOp[0].Head))\r
-#define ICMP_ERRLEN(IpHdr) \\r
-  (sizeof(IP4_ICMP_HEAD) + EFI_IP4_HEADER_LEN(IpHdr) + 8)\r
 \r
-NET_LIST_ENTRY  mActiveIpIoList = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mActiveIpIoList = {\r
   &mActiveIpIoList,\r
   &mActiveIpIoList\r
 };\r
 \r
-EFI_IP4_CONFIG_DATA  mIpIoDefaultIpConfigData = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA  mIp4IoDefaultIpConfigData = {\r
   EFI_IP_PROTO_UDP,\r
   FALSE,\r
   TRUE,\r
@@ -58,27 +41,67 @@ EFI_IP4_CONFIG_DATA  mIpIoDefaultIpConfigData = {
   0\r
 };\r
 \r
-STATIC ICMP_ERROR_INFO  mIcmpErrMap[10] = {\r
-  {FALSE, TRUE},\r
-  {FALSE, TRUE},\r
-  {TRUE, TRUE},\r
-  {TRUE, TRUE},\r
-  {TRUE, TRUE},\r
-  {FALSE, TRUE},\r
-  {FALSE, TRUE},\r
-  {FALSE, TRUE},\r
-  {FALSE, FALSE},\r
-  {FALSE, TRUE}\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA  mIp6IoDefaultIpConfigData = {\r
+  EFI_IP_PROTO_UDP,\r
+  FALSE,\r
+  TRUE,\r
+  FALSE,\r
+  {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
+  {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
+  0,\r
+  255,\r
+  0,\r
+  0,\r
+  0\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmpErrMap[10] = {\r
+  {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET\r
+  {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST\r
+  {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PROTOCOL\r
+  {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PORT\r
+  {TRUE,  TRUE }, // ICMP_ERR_MSGSIZE\r
+  {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL\r
+  {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS\r
+  {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS\r
+  {FALSE, FALSE}, // ICMP_ERR_QUENCH\r
+  {FALSE, TRUE }  // ICMP_ERR_PARAMPROB\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmp6ErrMap[10] = {\r
+  {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET\r
+  {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST\r
+  {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL\r
+  {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PORT\r
+  {TRUE,  TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG\r
+  {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT\r
+  {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS\r
+  {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER\r
+  {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER\r
+  {FALSE, TRUE}  // ICMP6_ERR_PARAMPROB_IPV6OPTION\r
 };\r
 \r
-STATIC\r
+\r
+/**\r
+  Notify function for IP transmit token.\r
+\r
+  @param[in]  Context               The context passed in by the event notifier.\r
+\r
+**/\r
 VOID\r
 EFIAPI\r
 IpIoTransmitHandlerDpc (\r
   IN VOID      *Context\r
   );\r
 \r
-STATIC\r
+\r
+/**\r
+  Notify function for IP transmit token.\r
+\r
+  @param[in]  Event                 The event signaled.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
+\r
+**/\r
 VOID\r
 EFIAPI\r
 IpIoTransmitHandler (\r
@@ -88,37 +111,52 @@ IpIoTransmitHandler (
 \r
 \r
 /**\r
-  This function create an ip child ,open the IP protocol, return the opened\r
-  Ip protocol to Interface.\r
+  This function create an IP child ,open the IP protocol, and return the opened\r
+  IP protocol as Interface.\r
 \r
-  @param  ControllerHandle      The controller handle.\r
-  @param  ImageHandle           The image handle.\r
-  @param  ChildHandle           Pointer to the buffer to save the ip child handle.\r
-  @param  Interface             Pointer used to get the ip protocol interface.\r
+  @param[in]    ControllerHandle   The controller handle.\r
+  @param[in]    ImageHandle        The image handle.\r
+  @param[in]    ChildHandle        Pointer to the buffer to save the IP child handle.\r
+  @param[in]    IpVersion          The version of the IP protocol to use, either\r
+                                   IPv4 or IPv6.\r
+  @param[out]   Interface          Pointer used to get the IP protocol interface.\r
 \r
-  @retval EFI_SUCCESS           The ip child is created and the ip protocol\r
-                                interface is retrieved.\r
-  @retval other                 The required operation failed.\r
+  @retval       EFI_SUCCESS        The IP child is created and the IP protocol\r
+                                   interface is retrieved.\r
+  @retval       EFI_UNSUPPORTED    Upsupported IpVersion.\r
+  @retval       Others             The required operation failed.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 IpIoCreateIpChildOpenProtocol (\r
   IN  EFI_HANDLE  ControllerHandle,\r
   IN  EFI_HANDLE  ImageHandle,\r
   IN  EFI_HANDLE  *ChildHandle,\r
+  IN  UINT8       IpVersion,\r
   OUT VOID        **Interface\r
   )\r
 {\r
   EFI_STATUS  Status;\r
+  EFI_GUID    *ServiceBindingGuid;\r
+  EFI_GUID    *IpProtocolGuid;\r
+\r
+  if (IpVersion == IP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;\r
+    IpProtocolGuid     = &gEfiIp4ProtocolGuid;\r
+  } else if (IpVersion == IP_VERSION_6){\r
+    ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;\r
+    IpProtocolGuid     = &gEfiIp6ProtocolGuid;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
 \r
   //\r
-  // Create an ip child.\r
+  // Create an IP child.\r
   //\r
   Status = NetLibCreateServiceChild (\r
              ControllerHandle,\r
              ImageHandle,\r
-             &gEfiIp4ServiceBindingProtocolGuid,\r
+             ServiceBindingGuid,\r
              ChildHandle\r
              );\r
   if (EFI_ERROR (Status)) {\r
@@ -126,11 +164,11 @@ IpIoCreateIpChildOpenProtocol (
   }\r
 \r
   //\r
-  // Open the ip protocol installed on the *ChildHandle.\r
+  // Open the IP protocol installed on the *ChildHandle.\r
   //\r
   Status = gBS->OpenProtocol (\r
                   *ChildHandle,\r
-                  &gEfiIp4ProtocolGuid,\r
+                  IpProtocolGuid,\r
                   Interface,\r
                   ImageHandle,\r
                   ControllerHandle,\r
@@ -138,12 +176,12 @@ IpIoCreateIpChildOpenProtocol (
                   );\r
   if (EFI_ERROR (Status)) {\r
     //\r
-    // On failure, destroy the ip child.\r
+    // On failure, destroy the IP child.\r
     //\r
     NetLibDestroyServiceChild (\r
       ControllerHandle,\r
       ImageHandle,\r
-      &gEfiIp4ServiceBindingProtocolGuid,\r
+      ServiceBindingGuid,\r
       *ChildHandle\r
       );\r
   }\r
@@ -153,84 +191,108 @@ IpIoCreateIpChildOpenProtocol (
 \r
 \r
 /**\r
-  This function close the previously openned ip protocol and destroy the ip child.\r
+  This function close the previously openned IP protocol and destroy the IP child.\r
 \r
-  @param  ControllerHandle      The controller handle.\r
-  @param  ImageHandle           the image handle.\r
-  @param  ChildHandle           The child handle of the ip child.\r
+  @param[in]  ControllerHandle    The controller handle.\r
+  @param[in]  ImageHandle         The image handle.\r
+  @param[in]  ChildHandle         The child handle of the IP child.\r
+  @param[in]  IpVersion           The version of the IP protocol to use, either\r
+                                  IPv4 or IPv6.\r
 \r
-  @retval EFI_SUCCESS           The ip protocol is closed and the relevant ip child\r
-                                is destroyed.\r
-  @retval other                 The required operation failed.\r
+  @retval     EFI_SUCCESS         The IP protocol is closed and the relevant IP child\r
+                                  is destroyed.\r
+  @retval     EFI_UNSUPPORTED     Upsupported IpVersion.\r
+  @retval     Others              The required operation failed.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 IpIoCloseProtocolDestroyIpChild (\r
   IN EFI_HANDLE  ControllerHandle,\r
   IN EFI_HANDLE  ImageHandle,\r
-  IN EFI_HANDLE  ChildHandle\r
+  IN EFI_HANDLE  ChildHandle,\r
+  IN UINT8       IpVersion\r
   )\r
 {\r
   EFI_STATUS  Status;\r
+  EFI_GUID    *ServiceBindingGuid;\r
+  EFI_GUID    *IpProtocolGuid;\r
+\r
+  if (IpVersion == IP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;\r
+    IpProtocolGuid     = &gEfiIp4ProtocolGuid;\r
+  } else if (IpVersion == IP_VERSION_6) {\r
+    ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;\r
+    IpProtocolGuid     = &gEfiIp6ProtocolGuid;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
 \r
   //\r
-  // Close the previously openned ip protocol.\r
+  // Close the previously openned IP protocol.\r
   //\r
-  gBS->CloseProtocol (\r
-         ChildHandle,\r
-         &gEfiIp4ProtocolGuid,\r
-         ImageHandle,\r
-         ControllerHandle\r
-         );\r
+  Status = gBS->CloseProtocol (\r
+                  ChildHandle,\r
+                  IpProtocolGuid,\r
+                  ImageHandle,\r
+                  ControllerHandle\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
   //\r
-  // Destroy the ip child.\r
+  // Destroy the IP child.\r
   //\r
-  Status = NetLibDestroyServiceChild (\r
-             ControllerHandle,\r
-             ImageHandle,\r
-             &gEfiIp4ServiceBindingProtocolGuid,\r
-             ChildHandle\r
-             );\r
-\r
-  return Status;\r
+  return NetLibDestroyServiceChild (\r
+           ControllerHandle,\r
+           ImageHandle,\r
+           ServiceBindingGuid,\r
+           ChildHandle\r
+           );\r
 }\r
 \r
-\r
 /**\r
-  Handle ICMP packets.\r
+  This function handles ICMPv4 packets. It is the worker function of\r
+  IpIoIcmpHandler.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance.\r
-  @param  Pkt                   Pointer to the ICMP packet.\r
-  @param  Session               Pointer to the net session of this ICMP packet.\r
+  @param[in]       IpIo            Pointer to the IP_IO instance.\r
+  @param[in, out]  Pkt             Pointer to the ICMPv4 packet.\r
+  @param[in]       Session         Pointer to the net session of this ICMPv4 packet.\r
 \r
-  @retval EFI_SUCCESS           The ICMP packet is handled successfully.\r
-  @retval EFI_ABORTED           This type of ICMP packet is not supported.\r
+  @retval          EFI_SUCCESS     The ICMPv4 packet is handled successfully.\r
+  @retval          EFI_ABORTED     This type of ICMPv4 packet is not supported.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
-IpIoIcmpHandler (\r
-  IN IP_IO                *IpIo,\r
-  IN NET_BUF              *Pkt,\r
-  IN EFI_NET_SESSION_DATA *Session\r
+IpIoIcmpv4Handler (\r
+  IN     IP_IO                *IpIo,\r
+  IN OUT NET_BUF              *Pkt,\r
+  IN     EFI_NET_SESSION_DATA *Session\r
   )\r
 {\r
   IP4_ICMP_ERROR_HEAD  *IcmpHdr;\r
   EFI_IP4_HEADER       *IpHdr;\r
-  ICMP_ERROR           IcmpErr;\r
+  UINT8                IcmpErr;\r
   UINT8                *PayLoadHdr;\r
   UINT8                Type;\r
   UINT8                Code;\r
   UINT32               TrimBytes;\r
 \r
-  IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);\r
-  IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);\r
+  ASSERT (IpIo != NULL);\r
+  ASSERT (Pkt != NULL);\r
+  ASSERT (Session != NULL);\r
+  ASSERT (IpIo->IpVersion == IP_VERSION_4);\r
 \r
   //\r
   // Check the ICMP packet length.\r
   //\r
+  if (Pkt->TotalSize < sizeof (IP4_ICMP_ERROR_HEAD)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);\r
+  IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);\r
+\r
   if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {\r
 \r
     return EFI_ABORTED;\r
@@ -250,7 +312,7 @@ IpIoIcmpHandler (
     case ICMP_CODE_UNREACH_PROTOCOL:\r
     case ICMP_CODE_UNREACH_PORT:\r
     case ICMP_CODE_UNREACH_SRCFAIL:\r
-      IcmpErr = (ICMP_ERROR) (ICMP_ERR_UNREACH_NET + Code);\r
+      IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);\r
 \r
       break;\r
 \r
@@ -276,8 +338,6 @@ IpIoIcmpHandler (
 \r
     default:\r
       return EFI_ABORTED;\r
-\r
-      break;\r
     }\r
 \r
     break;\r
@@ -287,7 +347,7 @@ IpIoIcmpHandler (
       return EFI_ABORTED;\r
     }\r
 \r
-    IcmpErr = (ICMP_ERROR) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
+    IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
 \r
     break;\r
 \r
@@ -311,8 +371,6 @@ IpIoIcmpHandler (
 \r
   default:\r
     return EFI_ABORTED;\r
-\r
-    break;\r
   }\r
 \r
   //\r
@@ -324,25 +382,232 @@ IpIoIcmpHandler (
 \r
   NetbufTrim (Pkt, TrimBytes, TRUE);\r
 \r
-  IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
+  //\r
+  // If the input packet has invalid format, and TrimBytes is larger than\r
+  // the packet size, the NetbufTrim might trim the packet to zero.\r
+  //\r
+  if (Pkt->TotalSize != 0) {\r
+    IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function handles ICMPv6 packets. It is the worker function of\r
+  IpIoIcmpHandler.\r
+\r
+  @param[in]       IpIo            Pointer to the IP_IO instance.\r
+  @param[in, out]  Pkt             Pointer to the ICMPv6 packet.\r
+  @param[in]       Session         Pointer to the net session of this ICMPv6 packet.\r
+\r
+  @retval          EFI_SUCCESS     The ICMPv6 packet is handled successfully.\r
+  @retval          EFI_ABORTED     This type of ICMPv6 packet is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+IpIoIcmpv6Handler (\r
+  IN     IP_IO                *IpIo,\r
+  IN OUT NET_BUF              *Pkt,\r
+  IN     EFI_NET_SESSION_DATA *Session\r
+  )\r
+{\r
+  IP6_ICMP_ERROR_HEAD  *IcmpHdr;\r
+  EFI_IP6_HEADER       *IpHdr;\r
+  UINT8                IcmpErr;\r
+  UINT8                *PayLoadHdr;\r
+  UINT8                Type;\r
+  UINT8                Code;\r
+  UINT8                NextHeader;\r
+  UINT32               TrimBytes;\r
+  BOOLEAN              Flag;\r
+\r
+  ASSERT (IpIo != NULL);\r
+  ASSERT (Pkt != NULL);\r
+  ASSERT (Session != NULL);\r
+  ASSERT (IpIo->IpVersion == IP_VERSION_6);\r
+\r
+  //\r
+  // Check the ICMPv6 packet length.\r
+  //\r
+  if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {\r
+\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);\r
+  Type    = IcmpHdr->Head.Type;\r
+  Code    = IcmpHdr->Head.Code;\r
+\r
+  //\r
+  // Analyze the ICMPv6 Error in this ICMPv6 packet\r
+  //\r
+  switch (Type) {\r
+  case ICMP_V6_DEST_UNREACHABLE:\r
+    switch (Code) {\r
+    case ICMP_V6_NO_ROUTE_TO_DEST:\r
+    case ICMP_V6_BEYOND_SCOPE:\r
+    case ICMP_V6_ROUTE_REJECTED:\r
+      IcmpErr = ICMP6_ERR_UNREACH_NET;\r
+\r
+      break;\r
+\r
+    case ICMP_V6_COMM_PROHIBITED:\r
+    case ICMP_V6_ADDR_UNREACHABLE:\r
+    case ICMP_V6_SOURCE_ADDR_FAILED:\r
+      IcmpErr = ICMP6_ERR_UNREACH_HOST;\r
+\r
+      break;\r
+\r
+    case ICMP_V6_PORT_UNREACHABLE:\r
+      IcmpErr = ICMP6_ERR_UNREACH_PORT;\r
+\r
+      break;\r
+\r
+     default:\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    break;\r
+\r
+  case ICMP_V6_PACKET_TOO_BIG:\r
+    if (Code >= 1) {\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;\r
+\r
+    break;\r
+\r
+  case ICMP_V6_TIME_EXCEEDED:\r
+    if (Code > 1) {\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);\r
+\r
+    break;\r
+\r
+  case ICMP_V6_PARAMETER_PROBLEM:\r
+    if (Code > 3) {\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);\r
+\r
+    break;\r
+\r
+   default:\r
+\r
+     return EFI_ABORTED;\r
+   }\r
+\r
+  //\r
+  // Notify user the ICMPv6 packet only containing payload except\r
+  // IPv6 basic header, extension header and ICMP header\r
+  //\r
+\r
+  IpHdr      = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);\r
+  NextHeader = IpHdr->NextHeader;\r
+  PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));\r
+  Flag       = TRUE;\r
+\r
+  do {\r
+    switch (NextHeader) {\r
+    case EFI_IP_PROTO_UDP:\r
+    case EFI_IP_PROTO_TCP:\r
+    case EFI_IP_PROTO_ICMP:\r
+    case IP6_NO_NEXT_HEADER:\r
+      Flag = FALSE;\r
+\r
+      break;\r
+\r
+    case IP6_HOP_BY_HOP:\r
+    case IP6_DESTINATION:\r
+      //\r
+      // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including\r
+      // the first 8 octets.\r
+      //\r
+      NextHeader = *(PayLoadHdr);\r
+      PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);\r
+\r
+      break;\r
+\r
+    case IP6_FRAGMENT:\r
+      //\r
+      // The Fragment Header Length is 8 octets.\r
+      //\r
+      NextHeader = *(PayLoadHdr);\r
+      PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);\r
+\r
+      break;\r
+\r
+    default:\r
+\r
+      return EFI_ABORTED;\r
+    }\r
+  } while (Flag);\r
+\r
+  TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);\r
+\r
+  NetbufTrim (Pkt, TrimBytes, TRUE);\r
+\r
+  //\r
+  // If the input packet has invalid format, and TrimBytes is larger than\r
+  // the packet size, the NetbufTrim might trim the packet to zero.\r
+  //\r
+  if (Pkt->TotalSize != 0) {\r
+    IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This function handles ICMP packets.\r
+\r
+  @param[in]       IpIo            Pointer to the IP_IO instance.\r
+  @param[in, out]  Pkt             Pointer to the ICMP packet.\r
+  @param[in]       Session         Pointer to the net session of this ICMP packet.\r
+\r
+  @retval          EFI_SUCCESS     The ICMP packet is handled successfully.\r
+  @retval          EFI_ABORTED     This type of ICMP packet is not supported.\r
+  @retval          EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+IpIoIcmpHandler (\r
+  IN     IP_IO                *IpIo,\r
+  IN OUT NET_BUF              *Pkt,\r
+  IN     EFI_NET_SESSION_DATA *Session\r
+  )\r
+{\r
+\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
+\r
+    return IpIoIcmpv4Handler (IpIo, Pkt, Session);\r
+\r
+  } else if (IpIo->IpVersion == IP_VERSION_6) {\r
+\r
+    return IpIoIcmpv6Handler (IpIo, Pkt, Session);\r
+\r
+  } else {\r
+\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+}\r
+\r
 \r
 /**\r
-  Ext free function for net buffer. This function is\r
-  called when the net buffer is freed. It is used to\r
+  Free function for receive token of IP_IO. It is used to\r
   signal the recycle event to notify IP to recycle the\r
   data buffer.\r
 \r
-  @param  Event                 The event to be signaled.\r
-\r
-  @return None.\r
+  @param[in]  Event                 The event to be signaled.\r
 \r
 **/\r
-STATIC\r
 VOID\r
+EFIAPI\r
 IpIoExtFree (\r
   IN VOID  *Event\r
   )\r
@@ -355,140 +620,177 @@ IpIoExtFree (
   Create a send entry to wrap a packet before sending\r
   out it through IP.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance.\r
-  @param  Pkt                   Pointer to the packet.\r
-  @param  Sender                Pointer to the IP sender.\r
-  @param  NotifyData            Pointer to the notify data.\r
-  @param  Dest                  Pointer to the destination IP address.\r
-  @param  Override              Pointer to the overriden IP_IO data.\r
+  @param[in, out]  IpIo                 Pointer to the IP_IO instance.\r
+  @param[in, out]  Pkt                  Pointer to the packet.\r
+  @param[in]       Sender               Pointer to the IP sender.\r
+  @param[in]       Context              Pointer to the context.\r
+  @param[in]       NotifyData           Pointer to the notify data.\r
+  @param[in]       Dest                 Pointer to the destination IP address.\r
+  @param[in]       Override             Pointer to the overriden IP_IO data.\r
 \r
-  @return Pointer to the data structure created to wrap the packet. If NULL,\r
-  @return resource limit occurred.\r
+  @return Pointer to the data structure created to wrap the packet. If any error occurs,\r
+          then return NULL.\r
 \r
 **/\r
-STATIC\r
 IP_IO_SEND_ENTRY *\r
 IpIoCreateSndEntry (\r
-  IN IP_IO             *IpIo,\r
-  IN NET_BUF           *Pkt,\r
-  IN EFI_IP4_PROTOCOL  *Sender,\r
-  IN VOID              *Context    OPTIONAL,\r
-  IN VOID              *NotifyData OPTIONAL,\r
-  IN IP4_ADDR          Dest,\r
-  IN IP_IO_OVERRIDE    *Override\r
+  IN OUT IP_IO             *IpIo,\r
+  IN OUT NET_BUF           *Pkt,\r
+  IN     IP_IO_IP_PROTOCOL Sender,\r
+  IN     VOID              *Context    OPTIONAL,\r
+  IN     VOID              *NotifyData OPTIONAL,\r
+  IN     EFI_IP_ADDRESS    *Dest       OPTIONAL,\r
+  IN     IP_IO_OVERRIDE    *Override\r
   )\r
 {\r
   IP_IO_SEND_ENTRY          *SndEntry;\r
-  EFI_IP4_COMPLETION_TOKEN  *SndToken;\r
-  EFI_IP4_TRANSMIT_DATA     *TxData;\r
+  EFI_EVENT                 Event;\r
   EFI_STATUS                Status;\r
-  EFI_IP4_OVERRIDE_DATA     *OverrideData;\r
-  volatile UINT32           Index;\r
+  NET_FRAGMENT              *ExtFragment;\r
+  UINT32                    FragmentCount;\r
+  IP_IO_OVERRIDE            *OverrideData;\r
+  IP_IO_IP_TX_DATA          *TxData;\r
+  EFI_IP4_TRANSMIT_DATA     *Ip4TxData;\r
+  EFI_IP6_TRANSMIT_DATA     *Ip6TxData;\r
+\r
+  if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {\r
+    return NULL;\r
+  }\r
+\r
+  Event        = NULL;\r
+  TxData       = NULL;\r
+  OverrideData = NULL;\r
 \r
   //\r
   // Allocate resource for SndEntry\r
   //\r
-  SndEntry = NetAllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
+  SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
   if (NULL == SndEntry) {\r
     return NULL;\r
   }\r
 \r
-  //\r
-  // Allocate resource for SndToken\r
-  //\r
-  SndToken = NetAllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));\r
-  if (NULL == SndToken) {\r
-    goto ReleaseSndEntry;\r
-  }\r
-\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  NET_TPL_EVENT,\r
+                  TPL_NOTIFY,\r
                   IpIoTransmitHandler,\r
                   SndEntry,\r
-                  &(SndToken->Event)\r
+                  &Event\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseSndToken;\r
+    goto ON_ERROR;\r
   }\r
 \r
+  FragmentCount = Pkt->BlockOpNum;\r
+\r
   //\r
   // Allocate resource for TxData\r
   //\r
-  TxData = NetAllocatePool (\r
-    sizeof (EFI_IP4_TRANSMIT_DATA) +\r
-    sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)\r
+  TxData = (IP_IO_IP_TX_DATA *) AllocatePool (\r
+    sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)\r
     );\r
 \r
   if (NULL == TxData) {\r
-    goto ReleaseEvent;\r
+    goto ON_ERROR;\r
   }\r
 \r
+  //\r
+  // Build a fragment table to contain the fragments in the packet.\r
+  //\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
+    ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;\r
+  } else {\r
+    ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;\r
+  }\r
+\r
+  NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);\r
+\r
+\r
   //\r
   // Allocate resource for OverrideData if needed\r
   //\r
-  OverrideData = NULL;\r
   if (NULL != Override) {\r
 \r
-    OverrideData = NetAllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));\r
+    OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);\r
     if (NULL == OverrideData) {\r
-      goto ReleaseResource;\r
+      goto ON_ERROR;\r
     }\r
-    //\r
-    // Set the fields of OverrideData\r
-    //\r
-    CopyMem (OverrideData, Override, sizeof (*OverrideData));\r
   }\r
 \r
   //\r
-  // Set the fields of TxData\r
+  // Set other fields of TxData except the fragment table\r
   //\r
-  NetCopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));\r
-  TxData->OverrideData                  = OverrideData;\r
-  TxData->OptionsLength                 = 0;\r
-  TxData->OptionsBuffer                 = NULL;\r
-  TxData->TotalDataLength               = Pkt->TotalSize;\r
-  TxData->FragmentCount                 = Pkt->BlockOpNum;\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
 \r
+    Ip4TxData = &TxData->Ip4TxData;\r
 \r
-  for (Index = 0; Index < Pkt->BlockOpNum; Index++) {\r
-    TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;\r
-    TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;\r
-  }\r
+    IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);\r
 \r
-  //\r
-  // Set the fields of SndToken\r
-  //\r
-  SndToken->Packet.TxData = TxData;\r
+    Ip4TxData->OverrideData    = &OverrideData->Ip4OverrideData;\r
+    Ip4TxData->OptionsLength   = 0;\r
+    Ip4TxData->OptionsBuffer   = NULL;\r
+    Ip4TxData->TotalDataLength = Pkt->TotalSize;\r
+    Ip4TxData->FragmentCount   = FragmentCount;\r
+\r
+    //\r
+    // Set the fields of SndToken\r
+    //\r
+    SndEntry->SndToken.Ip4Token.Event         = Event;\r
+    SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;\r
+  } else {\r
+\r
+    Ip6TxData = &TxData->Ip6TxData;\r
+\r
+    if (Dest != NULL) {\r
+      CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));\r
+    } else {\r
+      ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));\r
+    }\r
+\r
+    Ip6TxData->OverrideData  = &OverrideData->Ip6OverrideData;\r
+    Ip6TxData->DataLength    = Pkt->TotalSize;\r
+    Ip6TxData->FragmentCount = FragmentCount;\r
+    Ip6TxData->ExtHdrsLength = 0;\r
+    Ip6TxData->ExtHdrs       = NULL;\r
+\r
+    //\r
+    // Set the fields of SndToken\r
+    //\r
+    SndEntry->SndToken.Ip6Token.Event         = Event;\r
+    SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;\r
+  }\r
 \r
   //\r
   // Set the fields of SndEntry\r
   //\r
   SndEntry->IpIo        = IpIo;\r
-  SndEntry->Ip      = Sender;\r
+  SndEntry->Ip          = Sender;\r
   SndEntry->Context     = Context;\r
   SndEntry->NotifyData  = NotifyData;\r
 \r
   SndEntry->Pkt         = Pkt;\r
   NET_GET_REF (Pkt);\r
 \r
-  SndEntry->SndToken = SndToken;\r
-\r
-  NetListInsertTail (&IpIo->PendingSndList, &SndEntry->Entry);\r
+  InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);\r
 \r
   return SndEntry;\r
 \r
-ReleaseResource:\r
-  NetFreePool (TxData);\r
+ON_ERROR:\r
+\r
+  if (OverrideData != NULL) {\r
+    FreePool (OverrideData);\r
+  }\r
 \r
-ReleaseEvent:\r
-  gBS->CloseEvent (SndToken->Event);\r
+  if (TxData != NULL) {\r
+    FreePool (TxData);\r
+  }\r
 \r
-ReleaseSndToken:\r
-  NetFreePool (SndToken);\r
+  if (SndEntry != NULL) {\r
+    FreePool (SndEntry);\r
+  }\r
 \r
-ReleaseSndEntry:\r
-  NetFreePool (SndEntry);\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
 \r
   return NULL;\r
 }\r
@@ -497,45 +799,54 @@ ReleaseSndEntry:
 /**\r
   Destroy the SndEntry.\r
 \r
-  @param  SndEntry              Pointer to the send entry to be destroyed.\r
+  This function pairs with IpIoCreateSndEntry().\r
 \r
-  @return None.\r
+  @param[in]  SndEntry              Pointer to the send entry to be destroyed.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 IpIoDestroySndEntry (\r
   IN IP_IO_SEND_ENTRY  *SndEntry\r
   )\r
 {\r
-  EFI_IP4_TRANSMIT_DATA  *TxData;\r
+  EFI_EVENT         Event;\r
+  IP_IO_IP_TX_DATA  *TxData;\r
+  IP_IO_OVERRIDE    *Override;\r
+\r
+  if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {\r
+    Event              = SndEntry->SndToken.Ip4Token.Event;\r
+    TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;\r
+    Override           = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;\r
+  } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {\r
+    Event              = SndEntry->SndToken.Ip6Token.Event;\r
+    TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;\r
+    Override           = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;\r
+  } else {\r
+    return ;\r
+  }\r
 \r
-  TxData = SndEntry->SndToken->Packet.TxData;\r
+  gBS->CloseEvent (Event);\r
 \r
-  if (NULL != TxData->OverrideData) {\r
-    NetFreePool (TxData->OverrideData);\r
+  FreePool (TxData);\r
+\r
+  if (NULL != Override) {\r
+    FreePool (Override);\r
   }\r
 \r
-  NetFreePool (TxData);\r
   NetbufFree (SndEntry->Pkt);\r
-  gBS->CloseEvent (SndEntry->SndToken->Event);\r
 \r
-  NetFreePool (SndEntry->SndToken);\r
-  NetListRemoveEntry (&SndEntry->Entry);\r
+  RemoveEntryList (&SndEntry->Entry);\r
 \r
-  NetFreePool (SndEntry);\r
+  FreePool (SndEntry);\r
 }\r
 \r
 \r
 /**\r
   Notify function for IP transmit token.\r
 \r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoTransmitHandlerDpc (\r
@@ -544,14 +855,23 @@ IpIoTransmitHandlerDpc (
 {\r
   IP_IO             *IpIo;\r
   IP_IO_SEND_ENTRY  *SndEntry;\r
+  EFI_STATUS        Status;\r
 \r
   SndEntry  = (IP_IO_SEND_ENTRY *) Context;\r
 \r
   IpIo      = SndEntry->IpIo;\r
 \r
-  if (IpIo->PktSentNotify && SndEntry->NotifyData) {\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
+    Status = SndEntry->SndToken.Ip4Token.Status;\r
+  } else if (IpIo->IpVersion == IP_VERSION_6){\r
+    Status = SndEntry->SndToken.Ip6Token.Status;\r
+  } else {\r
+    return ;\r
+  }\r
+\r
+  if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {\r
     IpIo->PktSentNotify (\r
-            SndEntry->SndToken->Status,\r
+            Status,\r
             SndEntry->Context,\r
             SndEntry->Ip,\r
             SndEntry->NotifyData\r
@@ -561,17 +881,14 @@ IpIoTransmitHandlerDpc (
   IpIoDestroySndEntry (SndEntry);\r
 }\r
 \r
+\r
 /**\r
   Notify function for IP transmit token.\r
 \r
-  @param  Event                 The event signaled.\r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Event                 The event signaled.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
 \r
 **/\r
-\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoTransmitHandler (\r
@@ -582,19 +899,16 @@ IpIoTransmitHandler (
   //\r
   // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK\r
   //\r
-  NetLibQueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
+  QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
 }\r
 \r
 \r
 /**\r
   The dummy handler for the dummy IP receive token.\r
 \r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoDummyHandlerDpc (\r
@@ -602,36 +916,71 @@ IpIoDummyHandlerDpc (
   )\r
 {\r
   IP_IO_IP_INFO             *IpInfo;\r
-  EFI_IP4_COMPLETION_TOKEN  *DummyToken;\r
+  EFI_STATUS                 Status;\r
+  EFI_EVENT                  RecycleEvent;\r
 \r
   IpInfo      = (IP_IO_IP_INFO *) Context;\r
-  DummyToken  = &(IpInfo->DummyRcvToken);\r
 \r
-  if (EFI_ABORTED == DummyToken->Status) {\r
+  if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {\r
+    return ;\r
+  }\r
+\r
+  RecycleEvent = NULL;\r
+\r
+  if (IpInfo->IpVersion == IP_VERSION_4) {\r
+    Status = IpInfo->DummyRcvToken.Ip4Token.Status;\r
+\r
+    if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {\r
+      RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;\r
+    }\r
+  } else {\r
+    Status = IpInfo->DummyRcvToken.Ip6Token.Status;\r
+\r
+    if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {\r
+      RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;\r
+    }\r
+  }\r
+\r
+\r
+\r
+  if (EFI_ABORTED == Status) {\r
     //\r
     // The reception is actively aborted by the consumer, directly return.\r
     //\r
     return;\r
-  } else if (EFI_SUCCESS == DummyToken->Status) {\r
-    ASSERT (DummyToken->Packet.RxData);\r
+  } else if (EFI_SUCCESS == Status) {\r
+    //\r
+    // Recycle the RxData.\r
+    //\r
+    ASSERT (RecycleEvent != NULL);\r
 \r
-    gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);\r
+    gBS->SignalEvent (RecycleEvent);\r
   }\r
 \r
-  IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);\r
+  //\r
+  // Continue the receive.\r
+  //\r
+  if (IpInfo->IpVersion == IP_VERSION_4) {\r
+    IpInfo->Ip.Ip4->Receive (\r
+                      IpInfo->Ip.Ip4,\r
+                      &IpInfo->DummyRcvToken.Ip4Token\r
+                      );\r
+  } else {\r
+    IpInfo->Ip.Ip6->Receive (\r
+                      IpInfo->Ip.Ip6,\r
+                      &IpInfo->DummyRcvToken.Ip6Token\r
+                      );\r
+  }\r
 }\r
 \r
 \r
 /**\r
-  Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK.\r
+  This function add IpIoDummyHandlerDpc to the end of the DPC queue.\r
 \r
-  @param  Event                 The event signaled.\r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Event                 The event signaled.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoDummyHandler (\r
@@ -642,7 +991,7 @@ IpIoDummyHandler (
   //\r
   // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK\r
   //\r
-  NetLibQueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
+  QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
 }\r
 \r
 \r
@@ -650,12 +999,9 @@ IpIoDummyHandler (
   Notify function for the IP receive token, used to process\r
   the received IP packets.\r
 \r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Context               The context passed in by the event notifier.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoListenHandlerDpc (\r
@@ -664,16 +1010,21 @@ IpIoListenHandlerDpc (
 {\r
   IP_IO                 *IpIo;\r
   EFI_STATUS            Status;\r
-  EFI_IP4_RECEIVE_DATA  *RxData;\r
-  EFI_IP4_PROTOCOL      *Ip;\r
+  IP_IO_IP_RX_DATA      *RxData;\r
   EFI_NET_SESSION_DATA  Session;\r
   NET_BUF               *Pkt;\r
 \r
-  IpIo    = (IP_IO *) Context;\r
+  IpIo = (IP_IO *) Context;\r
 \r
-  Ip      = IpIo->Ip;\r
-  Status  = IpIo->RcvToken.Status;\r
-  RxData  = IpIo->RcvToken.Packet.RxData;\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
+    Status = IpIo->RcvToken.Ip4Token.Status;\r
+    RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;\r
+  } else if (IpIo->IpVersion == IP_VERSION_6) {\r
+    Status = IpIo->RcvToken.Ip6Token.Status;\r
+    RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;\r
+  } else {\r
+    return;\r
+  }\r
 \r
   if (EFI_ABORTED == Status) {\r
     //\r
@@ -682,12 +1033,22 @@ IpIoListenHandlerDpc (
     return;\r
   }\r
 \r
-  if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {\r
+  if ((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) {\r
     //\r
-    // Only process the normal packets and the icmp error packets, if RxData is NULL\r
-    // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
-    // this should be a bug of the low layer (IP).\r
+    // Only process the normal packets and the icmp error packets.\r
     //\r
+    if (RxData != NULL) {\r
+      goto CleanUp;\r
+    } else {\r
+      goto Resume;\r
+    }\r
+  }\r
+\r
+  //\r
+  // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).\r
+  //\r
+  ASSERT (RxData != NULL);\r
+  if (RxData == NULL) {\r
     goto Resume;\r
   }\r
 \r
@@ -695,39 +1056,113 @@ IpIoListenHandlerDpc (
     goto CleanUp;\r
   }\r
 \r
-  if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&\r
-    !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
+  if (IpIo->IpVersion == IP_VERSION_4) {\r
+    ASSERT (RxData->Ip4RxData.Header != NULL);\r
+    if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) {\r
+      //\r
+      // The source address is a broadcast address, discard it.\r
+      //\r
+      goto CleanUp;\r
+    }\r
+    if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&\r
+        (IpIo->SubnetMask != 0) &&\r
+        IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&\r
+        !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {\r
+      //\r
+      // The source address doesn't match StationIp and it's not a unicast IP address, discard it.\r
+      //\r
+      goto CleanUp;\r
+    }\r
+\r
+    if (RxData->Ip4RxData.DataLength == 0) {\r
+      //\r
+      // Discard zero length data payload packet.\r
+      //\r
+      goto CleanUp;\r
+    }\r
+\r
     //\r
-    // The source address is not zero and it's not a unicast IP address, discard it.\r
+    // The fragment should always be valid for non-zero length packet.\r
     //\r
-    goto CleanUp;\r
-  }\r
+    ASSERT (RxData->Ip4RxData.FragmentCount != 0);\r
 \r
-  //\r
-  // Create a netbuffer representing packet\r
-  //\r
-  Pkt = NetbufFromExt (\r
-          (NET_FRAGMENT *) RxData->FragmentTable,\r
-          RxData->FragmentCount,\r
-          0,\r
-          0,\r
-          IpIoExtFree,\r
-          RxData->RecycleSignal\r
-          );\r
-  if (NULL == Pkt) {\r
-    goto CleanUp;\r
-  }\r
+    //\r
+    // Create a netbuffer representing IPv4 packet\r
+    //\r
+    Pkt = NetbufFromExt (\r
+            (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,\r
+            RxData->Ip4RxData.FragmentCount,\r
+            0,\r
+            0,\r
+            IpIoExtFree,\r
+            RxData->Ip4RxData.RecycleSignal\r
+            );\r
+    if (NULL == Pkt) {\r
+      goto CleanUp;\r
+    }\r
 \r
-  //\r
-  // Create a net session\r
-  //\r
-  Session.Source = EFI_IP4 (RxData->Header->SourceAddress);\r
-  Session.Dest   = EFI_IP4 (RxData->Header->DestinationAddress);\r
-  Session.IpHdr  = RxData->Header;\r
+    //\r
+    // Create a net session\r
+    //\r
+    Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);\r
+    Session.Dest.Addr[0]   = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);\r
+    Session.IpHdr.Ip4Hdr   = RxData->Ip4RxData.Header;\r
+    Session.IpHdrLen       = RxData->Ip4RxData.HeaderLength;\r
+    Session.IpVersion      = IP_VERSION_4;\r
+  } else {\r
+    ASSERT (RxData->Ip6RxData.Header != NULL);\r
+    if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {\r
+      goto CleanUp;\r
+    }\r
+\r
+    if (RxData->Ip6RxData.DataLength == 0) {\r
+      //\r
+      // Discard zero length data payload packet.\r
+      //\r
+      goto CleanUp;\r
+    }\r
+\r
+    //\r
+    // The fragment should always be valid for non-zero length packet.\r
+    //\r
+    ASSERT (RxData->Ip6RxData.FragmentCount != 0);\r
+\r
+    //\r
+    // Create a netbuffer representing IPv6 packet\r
+    //\r
+    Pkt = NetbufFromExt (\r
+            (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,\r
+            RxData->Ip6RxData.FragmentCount,\r
+            0,\r
+            0,\r
+            IpIoExtFree,\r
+            RxData->Ip6RxData.RecycleSignal\r
+            );\r
+    if (NULL == Pkt) {\r
+      goto CleanUp;\r
+    }\r
+\r
+    //\r
+    // Create a net session\r
+    //\r
+    CopyMem (\r
+      &Session.Source,\r
+      &RxData->Ip6RxData.Header->SourceAddress,\r
+      sizeof(EFI_IPv6_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &Session.Dest,\r
+      &RxData->Ip6RxData.Header->DestinationAddress,\r
+      sizeof(EFI_IPv6_ADDRESS)\r
+      );\r
+    Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;\r
+    Session.IpHdrLen     = RxData->Ip6RxData.HeaderLength;\r
+    Session.IpVersion    = IP_VERSION_6;\r
+  }\r
 \r
   if (EFI_SUCCESS == Status) {\r
 \r
-    IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);\r
+    IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);\r
   } else {\r
     //\r
     // Status is EFI_ICMP_ERROR\r
@@ -741,23 +1176,29 @@ IpIoListenHandlerDpc (
   goto Resume;\r
 \r
 CleanUp:\r
-  gBS->SignalEvent (RxData->RecycleSignal);\r
+\r
+  if (IpIo->IpVersion == IP_VERSION_4){\r
+    gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);\r
+  } else {\r
+    gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);\r
+  }\r
 \r
 Resume:\r
-  Ip->Receive (Ip, &(IpIo->RcvToken));\r
-}\r
 \r
+  if (IpIo->IpVersion == IP_VERSION_4){\r
+    IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));\r
+  } else {\r
+    IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));\r
+  }\r
+}\r
 \r
 /**\r
-  Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
+  This function add IpIoListenHandlerDpc to the end of the DPC queue.\r
 \r
-  @param  Event                 The event signaled.\r
-  @param  Context               The context passed in by the event notifier.\r
-\r
-  @return None.\r
+  @param[in]  Event                The event signaled.\r
+  @param[in]  Context              The context passed in by the event notifier.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 IpIoListenHandler (\r
@@ -768,50 +1209,71 @@ IpIoListenHandler (
   //\r
   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
   //\r
-  NetLibQueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
+  QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
 }\r
 \r
 \r
 /**\r
   Create a new IP_IO instance.\r
 \r
-  @param  Image                 The image handle of an IP_IO consumer protocol.\r
-  @param  Controller            The controller handle of an IP_IO consumer protocol\r
-                                installed on.\r
+  If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
+\r
+  This function uses IP4/IP6 service binding protocol in Controller to create\r
+  an IP4/IP6 child (aka IP4/IP6 instance).\r
 \r
-  @return Pointer to a newly created IP_IO instance.\r
+  @param[in]  Image             The image handle of the driver or application that\r
+                                consumes IP_IO.\r
+  @param[in]  Controller        The controller handle that has IP4 or IP6 service\r
+                                binding protocol installed.\r
+  @param[in]  IpVersion         The version of the IP protocol to use, either\r
+                                IPv4 or IPv6.\r
+\r
+  @return Pointer to a newly created IP_IO instance, or NULL if failed.\r
 \r
 **/\r
 IP_IO *\r
+EFIAPI\r
 IpIoCreate (\r
   IN EFI_HANDLE Image,\r
-  IN EFI_HANDLE Controller\r
+  IN EFI_HANDLE Controller,\r
+  IN UINT8      IpVersion\r
   )\r
 {\r
   EFI_STATUS  Status;\r
   IP_IO       *IpIo;\r
+  EFI_EVENT   Event;\r
 \r
-  IpIo = NetAllocateZeroPool (sizeof (IP_IO));\r
+  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
+\r
+  IpIo = AllocateZeroPool (sizeof (IP_IO));\r
   if (NULL == IpIo) {\r
     return NULL;\r
   }\r
 \r
-  NetListInit (&(IpIo->PendingSndList));\r
-  NetListInit (&(IpIo->IpList));\r
+  InitializeListHead (&(IpIo->PendingSndList));\r
+  InitializeListHead (&(IpIo->IpList));\r
   IpIo->Controller  = Controller;\r
   IpIo->Image       = Image;\r
+  IpIo->IpVersion   = IpVersion;\r
+  Event             = NULL;\r
 \r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  NET_TPL_EVENT,\r
+                  TPL_NOTIFY,\r
                   IpIoListenHandler,\r
                   IpIo,\r
-                  &(IpIo->RcvToken.Event)\r
+                  &Event\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseIpIo;\r
   }\r
 \r
+  if (IpVersion == IP_VERSION_4) {\r
+    IpIo->RcvToken.Ip4Token.Event = Event;\r
+  } else {\r
+    IpIo->RcvToken.Ip6Token.Event = Event;\r
+  }\r
+\r
   //\r
   // Create an IP child and open IP protocol\r
   //\r
@@ -819,7 +1281,8 @@ IpIoCreate (
              Controller,\r
              Image,\r
              &IpIo->ChildHandle,\r
-             (VOID **)&(IpIo->Ip)\r
+             IpVersion,\r
+             (VOID **) & (IpIo->Ip)\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseIpIo;\r
@@ -829,11 +1292,11 @@ IpIoCreate (
 \r
 ReleaseIpIo:\r
 \r
-  if (NULL != IpIo->RcvToken.Event) {\r
-    gBS->CloseEvent (IpIo->RcvToken.Event);\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
   }\r
 \r
-  NetFreePool (IpIo);\r
+  gBS->FreePool (IpIo);\r
 \r
   return NULL;\r
 }\r
@@ -842,46 +1305,98 @@ ReleaseIpIo:
 /**\r
   Open an IP_IO instance for use.\r
 \r
-  @param  IpIo                  Pointer to an IP_IO instance that needs to open.\r
-  @param  OpenData              The configuration data for the IP_IO instance.\r
+  If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
 \r
-  @retval EFI_SUCCESS           The IP_IO instance opened with OpenData\r
-                                successfully.\r
-  @retval other                 Error condition occurred.\r
+  This function is called after IpIoCreate(). It is used for configuring the IP\r
+  instance and register the callbacks and their context data for sending and\r
+  receiving IP packets.\r
+\r
+  @param[in, out]  IpIo               Pointer to an IP_IO instance that needs\r
+                                      to open.\r
+  @param[in]       OpenData           The configuration data and callbacks for\r
+                                      the IP_IO instance.\r
+\r
+  @retval          EFI_SUCCESS            The IP_IO instance opened with OpenData\r
+                                          successfully.\r
+  @retval          EFI_ACCESS_DENIED      The IP_IO instance is configured, avoid to\r
+                                          reopen it.\r
+  @retval          EFI_UNSUPPORTED        IPv4 RawData mode is no supported.\r
+  @retval          EFI_INVALID_PARAMETER  Invalid input parameter.\r
+  @retval          Others                 Error condition occurred.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoOpen (\r
-  IN IP_IO           *IpIo,\r
-  IN IP_IO_OPEN_DATA *OpenData\r
+  IN OUT IP_IO           *IpIo,\r
+  IN     IP_IO_OPEN_DATA *OpenData\r
   )\r
 {\r
   EFI_STATUS        Status;\r
-  EFI_IP4_PROTOCOL  *Ip;\r
+  UINT8             IpVersion;\r
+\r
+  if (IpIo == NULL || OpenData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   if (IpIo->IsConfigured) {\r
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
-  Ip = IpIo->Ip;\r
+  IpVersion = IpIo->IpVersion;\r
+\r
+  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
 \r
   //\r
   // configure ip\r
   //\r
-  Status = Ip->Configure (Ip, &OpenData->IpConfigData);\r
+  if (IpVersion == IP_VERSION_4){\r
+    //\r
+    // RawData mode is no supported.\r
+    //\r
+    ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);\r
+    if (OpenData->IpConfigData.Ip4CfgData.RawData) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {\r
+      IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);\r
+      IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);\r
+    }\r
+\r
+    Status = IpIo->Ip.Ip4->Configure (\r
+                             IpIo->Ip.Ip4,\r
+                             &OpenData->IpConfigData.Ip4CfgData\r
+                             );\r
+  } else {\r
+\r
+    Status = IpIo->Ip.Ip6->Configure (\r
+                             IpIo->Ip.Ip6,\r
+                             &OpenData->IpConfigData.Ip6CfgData\r
+                             );\r
+  }\r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   //\r
-  // bugbug: to delete the default route entry in this Ip, if it is:\r
-  // (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
-  // its code\r
+  // @bug To delete the default route entry in this Ip, if it is:\r
+  // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
+  // @bug its code\r
   //\r
-  Status = Ip->Routes (Ip, TRUE, &mZeroIp4Addr, &mZeroIp4Addr, &mZeroIp4Addr);\r
+  if (IpVersion == IP_VERSION_4){\r
+    Status = IpIo->Ip.Ip4->Routes (\r
+                             IpIo->Ip.Ip4,\r
+                             TRUE,\r
+                             &mZeroIp4Addr,\r
+                             &mZeroIp4Addr,\r
+                             &mZeroIp4Addr\r
+                             );\r
 \r
-  if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
-    return Status;\r
+    if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
@@ -890,21 +1405,36 @@ IpIoOpen (
   IpIo->RcvdContext   = OpenData->RcvdContext;\r
   IpIo->SndContext    = OpenData->SndContext;\r
 \r
-  IpIo->Protocol      = OpenData->IpConfigData.DefaultProtocol;\r
+  if (IpVersion == IP_VERSION_4){\r
+    IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;\r
 \r
-  //\r
-  // start to listen incoming packet\r
-  //\r
-  Status = Ip->Receive (Ip, &(IpIo->RcvToken));\r
-  if (EFI_ERROR (Status)) {\r
-    Ip->Configure (Ip, NULL);\r
-    goto ErrorExit;\r
+    //\r
+    // start to listen incoming packet\r
+    //\r
+    Status = IpIo->Ip.Ip4->Receive (\r
+                             IpIo->Ip.Ip4,\r
+                             &(IpIo->RcvToken.Ip4Token)\r
+                             );\r
+    if (EFI_ERROR (Status)) {\r
+      IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
+      return Status;\r
+    }\r
+\r
+  } else {\r
+\r
+    IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;\r
+    Status = IpIo->Ip.Ip6->Receive (\r
+                             IpIo->Ip.Ip6,\r
+                             &(IpIo->RcvToken.Ip6Token)\r
+                             );\r
+    if (EFI_ERROR (Status)) {\r
+      IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
+      return Status;\r
+    }\r
   }\r
 \r
   IpIo->IsConfigured = TRUE;\r
-  NetListInsertTail (&mActiveIpIoList, &IpIo->Entry);\r
-\r
-ErrorExit:\r
+  InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
 \r
   return Status;\r
 }\r
@@ -913,36 +1443,53 @@ ErrorExit:
 /**\r
   Stop an IP_IO instance.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance that needs to stop.\r
+  If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
+\r
+  This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all\r
+  the pending send/receive tokens will be canceled.\r
+\r
+  @param[in, out]  IpIo            Pointer to the IP_IO instance that needs to stop.\r
 \r
-  @retval EFI_SUCCESS           The IP_IO instance stopped successfully.\r
-  @retval other                 Error condition occurred.\r
+  @retval          EFI_SUCCESS            The IP_IO instance stopped successfully.\r
+  @retval          EFI_INVALID_PARAMETER  Invalid input parameter.\r
+  @retval          Others                 Error condition occurred.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoStop (\r
-  IN IP_IO *IpIo\r
+  IN OUT IP_IO *IpIo\r
   )\r
 {\r
   EFI_STATUS        Status;\r
-  EFI_IP4_PROTOCOL  *Ip;\r
   IP_IO_IP_INFO     *IpInfo;\r
+  UINT8             IpVersion;\r
+\r
+  if (IpIo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   if (!IpIo->IsConfigured) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
+  IpVersion = IpIo->IpVersion;\r
+\r
+  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
+\r
   //\r
   // Remove the IpIo from the active IpIo list.\r
   //\r
-  NetListRemoveEntry (&IpIo->Entry);\r
-\r
-  Ip = IpIo->Ip;\r
+  RemoveEntryList (&IpIo->Entry);\r
 \r
   //\r
   // Configure NULL Ip\r
   //\r
-  Status = Ip->Configure (Ip, NULL);\r
+  if (IpVersion == IP_VERSION_4) {\r
+    Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
+  } else {\r
+    Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -953,21 +1500,25 @@ IpIoStop (
   // Detroy the Ip List used by IpIo\r
   //\r
 \r
-  while (!NetListIsEmpty (&(IpIo->IpList))) {\r
+  while (!IsListEmpty (&(IpIo->IpList))) {\r
     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
 \r
     IpIoRemoveIp (IpIo, IpInfo);\r
   }\r
 \r
   //\r
-  // All pending snd tokens should be flushed by reseting the IP instances.\r
+  // All pending send tokens should be flushed by resetting the IP instances.\r
   //\r
-  ASSERT (NetListIsEmpty (&IpIo->PendingSndList));\r
+  ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
 \r
   //\r
   // Close the receive event.\r
   //\r
-  gBS->CloseEvent (IpIo->RcvToken.Event);\r
+  if (IpVersion == IP_VERSION_4){\r
+    gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);\r
+  } else {\r
+    gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -976,29 +1527,46 @@ IpIoStop (
 /**\r
   Destroy an IP_IO instance.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance that needs to\r
-                                destroy.\r
+  This function is paired with IpIoCreate(). The IP_IO will be closed first.\r
+  Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().\r
+\r
+  @param[in, out]  IpIo         Pointer to the IP_IO instance that needs to be\r
+                                destroyed.\r
 \r
-  @retval EFI_SUCCESS           The IP_IO instance destroyed successfully.\r
-  @retval other                 Error condition occurred.\r
+  @retval          EFI_SUCCESS  The IP_IO instance destroyed successfully.\r
+  @retval          Others       Error condition occurred.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoDestroy (\r
-  IN IP_IO *IpIo\r
+  IN OUT IP_IO *IpIo\r
   )\r
 {\r
+  EFI_STATUS    Status;\r
+\r
   //\r
   // Stop the IpIo.\r
   //\r
-  IpIoStop (IpIo);\r
+  Status = IpIoStop (IpIo);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Close the IP protocol and destroy the child.\r
   //\r
-  IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpIo->ChildHandle);\r
+  Status = IpIoCloseProtocolDestroyIpChild (\r
+             IpIo->Controller,\r
+             IpIo->Image,\r
+             IpIo->ChildHandle,\r
+             IpIo->IpVersion\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-  NetFreePool (IpIo);\r
+  gBS->FreePool (IpIo);\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -1007,35 +1575,53 @@ IpIoDestroy (
 /**\r
   Send out an IP packet.\r
 \r
-  @param  IpIo                  Pointer to an IP_IO instance used for sending IP\r
-                                packet.\r
-  @param  Pkt                   Pointer to the IP packet to be sent.\r
-  @param  Sender                The IP protocol instance used for sending.\r
-  @param  NotifyData\r
-  @param  Dest                  The destination IP address to send this packet to.\r
-  @param  OverrideData          The data to override some configuration of the IP\r
-                                instance used for sending.\r
-\r
-  @retval EFI_SUCCESS           The operation is completed successfully.\r
-  @retval EFI_NOT_STARTED       The IpIo is not configured.\r
-  @retval EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
+  This function is called after IpIoOpen(). The data to be sent is wrapped in\r
+  Pkt. The IP instance wrapped in IpIo is used for sending by default but can be\r
+  overriden by Sender. Other sending configs, like source address and gateway\r
+  address etc., are specified in OverrideData.\r
+\r
+  @param[in, out]  IpIo                  Pointer to an IP_IO instance used for sending IP\r
+                                         packet.\r
+  @param[in, out]  Pkt                   Pointer to the IP packet to be sent.\r
+  @param[in]       Sender                The IP protocol instance used for sending.\r
+  @param[in]       Context               Optional context data.\r
+  @param[in]       NotifyData            Optional notify data.\r
+  @param[in]       Dest                  The destination IP address to send this packet to.\r
+                                         This parameter is optional when using IPv6.\r
+  @param[in]       OverrideData          The data to override some configuration of the IP\r
+                                         instance used for sending.\r
+\r
+  @retval          EFI_SUCCESS           The operation is completed successfully.\r
+  @retval          EFI_INVALID_PARAMETER The input parameter is not correct.\r
+  @retval          EFI_NOT_STARTED       The IpIo is not configured.\r
+  @retval          EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
+  @retval          Others                Error condition occurred.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoSend (\r
-  IN IP_IO           *IpIo,\r
-  IN NET_BUF         *Pkt,\r
-  IN IP_IO_IP_INFO   *Sender,\r
-  IN VOID            *Context    OPTIONAL,\r
-  IN VOID            *NotifyData OPTIONAL,\r
-  IN IP4_ADDR        Dest,\r
-  IN IP_IO_OVERRIDE  *OverrideData\r
+  IN OUT IP_IO          *IpIo,\r
+  IN OUT NET_BUF        *Pkt,\r
+  IN     IP_IO_IP_INFO  *Sender        OPTIONAL,\r
+  IN     VOID           *Context       OPTIONAL,\r
+  IN     VOID           *NotifyData    OPTIONAL,\r
+  IN     EFI_IP_ADDRESS *Dest          OPTIONAL,\r
+  IN     IP_IO_OVERRIDE *OverrideData  OPTIONAL\r
   )\r
 {\r
   EFI_STATUS        Status;\r
-  EFI_IP4_PROTOCOL  *Ip;\r
+  IP_IO_IP_PROTOCOL Ip;\r
   IP_IO_SEND_ENTRY  *SndEntry;\r
 \r
+  if ((IpIo == NULL) || (Pkt == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   if (!IpIo->IsConfigured) {\r
     return EFI_NOT_STARTED;\r
   }\r
@@ -1053,7 +1639,18 @@ IpIoSend (
   //\r
   // Send this Packet\r
   //\r
-  Status = Ip->Transmit (Ip, SndEntry->SndToken);\r
+  if (IpIo->IpVersion == IP_VERSION_4){\r
+    Status = Ip.Ip4->Transmit (\r
+                       Ip.Ip4,\r
+                       &SndEntry->SndToken.Ip4Token\r
+                       );\r
+  } else {\r
+    Status = Ip.Ip6->Transmit (\r
+                       Ip.Ip6,\r
+                       &SndEntry->SndToken.Ip6Token\r
+                       );\r
+  }\r
+\r
   if (EFI_ERROR (Status)) {\r
     IpIoDestroySndEntry (SndEntry);\r
   }\r
@@ -1065,23 +1662,25 @@ IpIoSend (
 /**\r
   Cancel the IP transmit token which wraps this Packet.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance.\r
-  @param  Packet                Pointer to the packet to cancel.\r
+  If IpIo is NULL, then ASSERT().\r
+  If Packet is NULL, then ASSERT().\r
 \r
-  @return N/A.\r
+  @param[in]  IpIo                  Pointer to the IP_IO instance.\r
+  @param[in]  Packet                Pointer to the packet of NET_BUF to cancel.\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 IpIoCancelTxToken (\r
   IN IP_IO  *IpIo,\r
   IN VOID   *Packet\r
   )\r
 {\r
-  NET_LIST_ENTRY    *Node;\r
+  LIST_ENTRY        *Node;\r
   IP_IO_SEND_ENTRY  *SndEntry;\r
-  EFI_IP4_PROTOCOL  *Ip;\r
+  IP_IO_IP_PROTOCOL Ip;\r
 \r
-  ASSERT (IpIo && Packet);\r
+  ASSERT ((IpIo != NULL) && (Packet != NULL));\r
 \r
   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
 \r
@@ -1090,7 +1689,18 @@ IpIoCancelTxToken (
     if (SndEntry->Pkt == Packet) {\r
 \r
       Ip = SndEntry->Ip;\r
-      Ip->Cancel (Ip, SndEntry->SndToken);\r
+\r
+      if (IpIo->IpVersion == IP_VERSION_4) {\r
+        Ip.Ip4->Cancel (\r
+                  Ip.Ip4,\r
+                  &SndEntry->SndToken.Ip4Token\r
+                  );\r
+      } else {\r
+        Ip.Ip6->Cancel (\r
+                  Ip.Ip6,\r
+                  &SndEntry->SndToken.Ip6Token\r
+                  );\r
+      }\r
 \r
       break;\r
     }\r
@@ -1102,44 +1712,57 @@ IpIoCancelTxToken (
 /**\r
   Add a new IP instance for sending data.\r
 \r
-  @param  IpIo                  Pointer to a IP_IO instance to add a new IP\r
-                                instance for sending purpose.\r
+  If IpIo is NULL, then ASSERT().\r
+  If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
+\r
+  The function is used to add the IP_IO to the IP_IO sending list. The caller\r
+  can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send\r
+  data.\r
 \r
-  @return Pointer to the created IP_IO_IP_INFO structure, NULL is failed.\r
+  @param[in, out]  IpIo               Pointer to a IP_IO instance to add a new IP\r
+                                      instance for sending purpose.\r
+\r
+  @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.\r
 \r
 **/\r
 IP_IO_IP_INFO *\r
+EFIAPI\r
 IpIoAddIp (\r
-  IN IP_IO  *IpIo\r
+  IN OUT IP_IO  *IpIo\r
   )\r
 {\r
   EFI_STATUS     Status;\r
   IP_IO_IP_INFO  *IpInfo;\r
+  EFI_EVENT      Event;\r
 \r
-  ASSERT (IpIo);\r
+  ASSERT (IpIo != NULL);\r
+  ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6));\r
 \r
-  IpInfo = NetAllocatePool (sizeof (IP_IO_IP_INFO));\r
+  IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
   if (IpInfo == NULL) {\r
-    return IpInfo;\r
+    return NULL;\r
   }\r
 \r
   //\r
   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
   // instance.\r
   //\r
-  NetListInit (&IpInfo->Entry);\r
+  InitializeListHead (&IpInfo->Entry);\r
   IpInfo->ChildHandle = NULL;\r
-  IpInfo->Addr        = 0;\r
-  IpInfo->SubnetMask  = 0;\r
-  IpInfo->RefCnt      = 1;\r
+  ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
+  ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
+\r
+  IpInfo->RefCnt    = 1;\r
+  IpInfo->IpVersion = IpIo->IpVersion;\r
 \r
   //\r
-  // Create the IP instance and open the Ip4 protocol.\r
+  // Create the IP instance and open the IP protocol.\r
   //\r
   Status = IpIoCreateIpChildOpenProtocol (\r
              IpIo->Controller,\r
              IpIo->Image,\r
              &IpInfo->ChildHandle,\r
+             IpInfo->IpVersion,\r
              (VOID **) &IpInfo->Ip\r
              );\r
   if (EFI_ERROR (Status)) {\r
@@ -1151,19 +1774,25 @@ IpIoAddIp (
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  NET_TPL_EVENT,\r
+                  TPL_NOTIFY,\r
                   IpIoDummyHandler,\r
                   IpInfo,\r
-                  &IpInfo->DummyRcvToken.Event\r
+                  &Event\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseIpChild;\r
   }\r
 \r
+  if (IpInfo->IpVersion == IP_VERSION_4) {\r
+    IpInfo->DummyRcvToken.Ip4Token.Event = Event;\r
+  } else {\r
+    IpInfo->DummyRcvToken.Ip6Token.Event = Event;\r
+  }\r
+\r
   //\r
   // Link this IpInfo into the IpIo.\r
   //\r
-  NetListInsertTail (&IpIo->IpList, &IpInfo->Entry);\r
+  InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
 \r
   return IpInfo;\r
 \r
@@ -1172,88 +1801,184 @@ ReleaseIpChild:
   IpIoCloseProtocolDestroyIpChild (\r
     IpIo->Controller,\r
     IpIo->Image,\r
-    IpInfo->ChildHandle\r
+    IpInfo->ChildHandle,\r
+    IpInfo->IpVersion\r
     );\r
 \r
 ReleaseIpInfo:\r
 \r
-  NetFreePool (IpInfo);\r
+  gBS->FreePool (IpInfo);\r
 \r
   return NULL;\r
 }\r
 \r
 \r
 /**\r
-  Configure the IP instance of this IpInfo and start the receiving if Ip4ConfigData\r
+  Configure the IP instance of this IpInfo and start the receiving if IpConfigData\r
   is not NULL.\r
 \r
-  @param  IpInfo                Pointer to the IP_IO_IP_INFO instance.\r
-  @param  Ip4ConfigData         The IP4 configure data used to configure the ip\r
-                                instance, if NULL the ip instance is reseted. If\r
-                                UseDefaultAddress is set to TRUE, and the configure\r
-                                operation succeeds, the default address information\r
-                                is written back in this Ip4ConfigData.\r
+  If IpInfo is NULL, then ASSERT().\r
+  If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
+\r
+  @param[in, out]  IpInfo          Pointer to the IP_IO_IP_INFO instance.\r
+  @param[in, out]  IpConfigData    The IP configure data used to configure the IP\r
+                                   instance, if NULL the IP instance is reset. If\r
+                                   UseDefaultAddress is set to TRUE, and the configure\r
+                                   operation succeeds, the default address information\r
+                                   is written back in this IpConfigData.\r
 \r
-  @retval EFI_STATUS            The status returned by IP4->Configure or\r
-                                IP4->Receive.\r
+  @retval          EFI_SUCCESS     The IP instance of this IpInfo is configured successfully\r
+                                   or no need to reconfigure it.\r
+  @retval          Others          Configuration fails.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoConfigIp (\r
-  IN     IP_IO_IP_INFO        *IpInfo,\r
-  IN OUT EFI_IP4_CONFIG_DATA  *Ip4ConfigData OPTIONAL\r
+  IN OUT IP_IO_IP_INFO        *IpInfo,\r
+  IN OUT VOID                 *IpConfigData OPTIONAL\r
   )\r
 {\r
   EFI_STATUS         Status;\r
-  EFI_IP4_PROTOCOL   *Ip;\r
+  IP_IO_IP_PROTOCOL  Ip;\r
+  UINT8              IpVersion;\r
   EFI_IP4_MODE_DATA  Ip4ModeData;\r
+  EFI_IP6_MODE_DATA  Ip6ModeData;\r
 \r
-  ASSERT (IpInfo);\r
+  ASSERT (IpInfo != NULL);\r
 \r
   if (IpInfo->RefCnt > 1) {\r
     //\r
     // This IP instance is shared, don't reconfigure it until it has only one\r
     // consumer. Currently, only the tcp children cloned from their passive parent\r
-    // will share the same IP. So this cases only happens while Ip4ConfigData is NULL,\r
+    // will share the same IP. So this cases only happens while IpConfigData is NULL,\r
     // let the last consumer clean the IP instance.\r
     //\r
     return EFI_SUCCESS;\r
   }\r
 \r
+  IpVersion = IpInfo->IpVersion;\r
+  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
+\r
   Ip = IpInfo->Ip;\r
 \r
-  Status = Ip->Configure (Ip, Ip4ConfigData);\r
+  if (IpInfo->IpVersion == IP_VERSION_4) {\r
+    Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);\r
+  } else {\r
+    Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);\r
+  }\r
+\r
   if (EFI_ERROR (Status)) {\r
-    goto OnExit;\r
+    return Status;\r
   }\r
 \r
-  if (Ip4ConfigData != NULL) {\r
+  if (IpConfigData != NULL) {\r
+    if (IpInfo->IpVersion == IP_VERSION_4) {\r
+\r
+      if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {\r
+        Status = Ip.Ip4->GetModeData (\r
+                           Ip.Ip4,\r
+                           &Ip4ModeData,\r
+                           NULL,\r
+                           NULL\r
+                           );\r
+        if (EFI_ERROR (Status)) {\r
+          Ip.Ip4->Configure (Ip.Ip4, NULL);\r
+          return Status;\r
+        }\r
+\r
+        IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);\r
+        IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);\r
+      }\r
 \r
-    if (Ip4ConfigData->UseDefaultAddress) {\r
-      Ip->GetModeData (Ip, &Ip4ModeData, NULL, NULL);\r
+      CopyMem (\r
+        &IpInfo->Addr.Addr,\r
+        &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,\r
+        sizeof (IP4_ADDR)\r
+        );\r
+      CopyMem (\r
+        &IpInfo->PreMask.SubnetMask,\r
+        &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,\r
+        sizeof (IP4_ADDR)\r
+        );\r
+\r
+      Status = Ip.Ip4->Receive (\r
+                         Ip.Ip4,\r
+                         &IpInfo->DummyRcvToken.Ip4Token\r
+                         );\r
+      if (EFI_ERROR (Status)) {\r
+        Ip.Ip4->Configure (Ip.Ip4, NULL);\r
+      }\r
+    } else {\r
+      Status = Ip.Ip6->GetModeData (\r
+                         Ip.Ip6,\r
+                         &Ip6ModeData,\r
+                         NULL,\r
+                         NULL\r
+                         );\r
+      if (EFI_ERROR (Status)) {\r
+        Ip.Ip6->Configure (Ip.Ip6, NULL);\r
+        return Status;\r
+      }\r
 \r
-      Ip4ConfigData->StationAddress = Ip4ModeData.ConfigData.StationAddress;\r
-      Ip4ConfigData->SubnetMask     = Ip4ModeData.ConfigData.SubnetMask;\r
-    }\r
+      if (Ip6ModeData.IsConfigured) {\r
+        CopyMem (\r
+          &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,\r
+          &Ip6ModeData.ConfigData.StationAddress,\r
+          sizeof (EFI_IPv6_ADDRESS)\r
+          );\r
 \r
-    NetCopyMem (&IpInfo->Addr, &Ip4ConfigData->StationAddress, sizeof (IP4_ADDR));\r
-    NetCopyMem (&IpInfo->SubnetMask, &Ip4ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
+        if (Ip6ModeData.AddressList != NULL) {\r
+          FreePool (Ip6ModeData.AddressList);\r
+        }\r
 \r
-    Status = Ip->Receive (Ip, &IpInfo->DummyRcvToken);\r
-    if (EFI_ERROR (Status)) {\r
-      Ip->Configure (Ip, NULL);\r
+        if (Ip6ModeData.GroupTable != NULL) {\r
+          FreePool (Ip6ModeData.GroupTable);\r
+        }\r
+\r
+        if (Ip6ModeData.RouteTable != NULL) {\r
+          FreePool (Ip6ModeData.RouteTable);\r
+        }\r
+\r
+        if (Ip6ModeData.NeighborCache != NULL) {\r
+          FreePool (Ip6ModeData.NeighborCache);\r
+        }\r
+\r
+        if (Ip6ModeData.PrefixTable != NULL) {\r
+          FreePool (Ip6ModeData.PrefixTable);\r
+        }\r
+\r
+        if (Ip6ModeData.IcmpTypeList != NULL) {\r
+          FreePool (Ip6ModeData.IcmpTypeList);\r
+        }\r
+\r
+      } else {\r
+        Status = EFI_NO_MAPPING;\r
+        return Status;\r
+      }\r
+\r
+      CopyMem (\r
+        &IpInfo->Addr,\r
+        &Ip6ModeData.ConfigData.StationAddress,\r
+        sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+\r
+      Status = Ip.Ip6->Receive (\r
+                         Ip.Ip6,\r
+                         &IpInfo->DummyRcvToken.Ip6Token\r
+                         );\r
+      if (EFI_ERROR (Status)) {\r
+        Ip.Ip6->Configure (Ip.Ip6, NULL);\r
+      }\r
     }\r
   } else {\r
-\r
     //\r
-    // The IP instance is reseted, set the stored Addr and SubnetMask to zero.\r
+    // The IP instance is reset, set the stored Addr and SubnetMask to zero.\r
     //\r
-    IpInfo->Addr       = 0;\r
-    IpInfo->SubnetMask =0;\r
+    ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
+    ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
   }\r
 \r
-OnExit:\r
-\r
   return Status;\r
 }\r
 \r
@@ -1262,18 +1987,30 @@ OnExit:
   Destroy an IP instance maintained in IpIo->IpList for\r
   sending purpose.\r
 \r
-  @param  IpIo                  Pointer to the IP_IO instance.\r
-  @param  IpInfo                Pointer to the IpInfo to be removed.\r
+  If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
 \r
-  @return None.\r
+  This function pairs with IpIoAddIp(). The IpInfo is previously created by\r
+  IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance\r
+  will be dstroyed if the RefCnt is zero.\r
+\r
+  @param[in]  IpIo                  Pointer to the IP_IO instance.\r
+  @param[in]  IpInfo                Pointer to the IpInfo to be removed.\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 IpIoRemoveIp (\r
-  IN IP_IO          *IpIo,\r
-  IN IP_IO_IP_INFO  *IpInfo\r
+  IN IP_IO            *IpIo,\r
+  IN IP_IO_IP_INFO    *IpInfo\r
   )\r
 {\r
+\r
+  UINT8               IpVersion;\r
+\r
+  if (IpIo == NULL || IpInfo == NULL) {\r
+    return;\r
+  }\r
+\r
   ASSERT (IpInfo->RefCnt > 0);\r
 \r
   NET_PUT_REF (IpInfo);\r
@@ -1283,53 +2020,106 @@ IpIoRemoveIp (
     return;\r
   }\r
 \r
-  NetListRemoveEntry (&IpInfo->Entry);\r
+  IpVersion = IpIo->IpVersion;\r
 \r
-  IpInfo->Ip->Configure (IpInfo->Ip, NULL);\r
+  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
 \r
-  IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpInfo->ChildHandle);\r
+  RemoveEntryList (&IpInfo->Entry);\r
 \r
-  gBS->CloseEvent (IpInfo->DummyRcvToken.Event);\r
+  if (IpVersion == IP_VERSION_4){\r
+    IpInfo->Ip.Ip4->Configure (\r
+                      IpInfo->Ip.Ip4,\r
+                      NULL\r
+                      );\r
+    IpIoCloseProtocolDestroyIpChild (\r
+      IpIo->Controller,\r
+      IpIo->Image,\r
+      IpInfo->ChildHandle,\r
+      IP_VERSION_4\r
+      );\r
+\r
+    gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);\r
+\r
+  } else {\r
 \r
-  NetFreePool (IpInfo);\r
+    IpInfo->Ip.Ip6->Configure (\r
+                      IpInfo->Ip.Ip6,\r
+                      NULL\r
+                      );\r
+\r
+    IpIoCloseProtocolDestroyIpChild (\r
+      IpIo->Controller,\r
+      IpIo->Image,\r
+      IpInfo->ChildHandle,\r
+      IP_VERSION_6\r
+      );\r
+\r
+    gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);\r
+  }\r
+\r
+  FreePool (IpInfo);\r
 }\r
 \r
 \r
 /**\r
   Find the first IP protocol maintained in IpIo whose local\r
-  address is the same with Src.\r
+  address is the same as Src.\r
+\r
+  This function is called when the caller needs the IpIo to send data to the\r
+  specified Src. The IpIo was added previously by IpIoAddIp().\r
 \r
-  @param  IpIo                  Pointer to the pointer of the IP_IO instance.\r
-  @param  Src                   The local IP address.\r
+  @param[in, out]  IpIo              Pointer to the pointer of the IP_IO instance.\r
+  @param[in]       IpVersion         The version of the IP protocol to use, either\r
+                                     IPv4 or IPv6.\r
+  @param[in]       Src               The local IP address.\r
 \r
   @return Pointer to the IP protocol can be used for sending purpose and its local\r
-  @return address is the same with Src.\r
+          address is the same with Src. NULL if failed.\r
 \r
 **/\r
 IP_IO_IP_INFO *\r
+EFIAPI\r
 IpIoFindSender (\r
-  IN OUT IP_IO     **IpIo,\r
-  IN     IP4_ADDR  Src\r
+  IN OUT IP_IO           **IpIo,\r
+  IN     UINT8           IpVersion,\r
+  IN     EFI_IP_ADDRESS  *Src\r
   )\r
 {\r
-  NET_LIST_ENTRY  *IpIoEntry;\r
+  LIST_ENTRY      *IpIoEntry;\r
   IP_IO           *IpIoPtr;\r
-  NET_LIST_ENTRY  *IpInfoEntry;\r
+  LIST_ENTRY      *IpInfoEntry;\r
   IP_IO_IP_INFO   *IpInfo;\r
 \r
+  if (IpIo == NULL || Src == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) {\r
+    return NULL;\r
+  }\r
+\r
   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
 \r
-    if ((*IpIo != NULL) && (*IpIo != IpIoPtr)) {\r
+    if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {\r
       continue;\r
     }\r
 \r
     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
+      if (IpInfo->IpVersion == IP_VERSION_4){\r
+\r
+        if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {\r
+          *IpIo = IpIoPtr;\r
+          return IpInfo;\r
+        }\r
+\r
+      } else {\r
 \r
-      if (IpInfo->Addr == Src) {\r
-        *IpIo = IpIoPtr;\r
-        return IpInfo;\r
+        if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {\r
+          *IpIo = IpIoPtr;\r
+          return IpInfo;\r
+        }\r
       }\r
     }\r
   }\r
@@ -1342,61 +2132,160 @@ IpIoFindSender (
 \r
 \r
 /**\r
-  Get the ICMP error map information, the ErrorStatus will be returned.\r
-  The IsHard and Notify are optional. If they are not NULL, this rouine will\r
-  fill them.\r
-  We move IcmpErrMap[] to local variable to enable EBC build.\r
+  Get the ICMP error map information.\r
 \r
-  @param  IcmpError             IcmpError Type\r
-  @param  IsHard                Whether it is a hard error\r
-  @param  Notify                Whether it need to notify SockError\r
+  The ErrorStatus will be returned. The IsHard and Notify are optional. If they\r
+  are not NULL, this routine will fill them.\r
 \r
-  @return ICMP Error Status\r
+  @param[in]   IcmpError             IcmpError Type.\r
+  @param[in]   IpVersion             The version of the IP protocol to use,\r
+                                     either IPv4 or IPv6.\r
+  @param[out]  IsHard                If TRUE, indicates that it is a hard error.\r
+  @param[out]  Notify                If TRUE, SockError needs to be notified.\r
+\r
+  @retval EFI_UNSUPPORTED            Unrecognizable ICMP error code.\r
+  @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.\r
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 IpIoGetIcmpErrStatus (\r
-  IN  ICMP_ERROR  IcmpError,\r
-  OUT BOOLEAN     *IsHard, OPTIONAL\r
-  OUT BOOLEAN     *Notify OPTIONAL\r
+  IN  UINT8       IcmpError,\r
+  IN  UINT8       IpVersion,\r
+  OUT BOOLEAN     *IsHard  OPTIONAL,\r
+  OUT BOOLEAN     *Notify  OPTIONAL\r
   )\r
 {\r
-  ASSERT ((IcmpError >= ICMP_ERR_UNREACH_NET) && (IcmpError <= ICMP_ERR_PARAMPROB));\r
+  if (IpVersion == IP_VERSION_4 ) {\r
+    ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);\r
 \r
-  if (IsHard != NULL) {\r
-    *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
-  }\r
+    if (IsHard != NULL) {\r
+      *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
+    }\r
+\r
+    if (Notify != NULL) {\r
+      *Notify = mIcmpErrMap[IcmpError].Notify;\r
+    }\r
+\r
+    switch (IcmpError) {\r
+    case ICMP_ERR_UNREACH_NET:\r
+      return  EFI_NETWORK_UNREACHABLE;\r
+\r
+    case ICMP_ERR_TIMXCEED_INTRANS:\r
+    case ICMP_ERR_TIMXCEED_REASS:\r
+    case ICMP_ERR_UNREACH_HOST:\r
+      return  EFI_HOST_UNREACHABLE;\r
+\r
+    case ICMP_ERR_UNREACH_PROTOCOL:\r
+      return  EFI_PROTOCOL_UNREACHABLE;\r
+\r
+    case ICMP_ERR_UNREACH_PORT:\r
+      return  EFI_PORT_UNREACHABLE;\r
+\r
+    case ICMP_ERR_MSGSIZE:\r
+    case ICMP_ERR_UNREACH_SRCFAIL:\r
+    case ICMP_ERR_QUENCH:\r
+    case ICMP_ERR_PARAMPROB:\r
+      return  EFI_ICMP_ERROR;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+  } else if (IpVersion == IP_VERSION_6) {\r
 \r
-  if (Notify != NULL) {\r
-    *Notify = mIcmpErrMap[IcmpError].Notify;\r
+    ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);\r
+\r
+    if (IsHard != NULL) {\r
+      *IsHard = mIcmp6ErrMap[IcmpError].IsHard;\r
+    }\r
+\r
+    if (Notify != NULL) {\r
+      *Notify = mIcmp6ErrMap[IcmpError].Notify;\r
+    }\r
+\r
+    switch (IcmpError) {\r
+    case ICMP6_ERR_UNREACH_NET:\r
+      return EFI_NETWORK_UNREACHABLE;\r
+\r
+    case ICMP6_ERR_UNREACH_HOST:\r
+    case ICMP6_ERR_TIMXCEED_HOPLIMIT:\r
+    case ICMP6_ERR_TIMXCEED_REASS:\r
+      return EFI_HOST_UNREACHABLE;\r
+\r
+    case ICMP6_ERR_UNREACH_PROTOCOL:\r
+      return EFI_PROTOCOL_UNREACHABLE;\r
+\r
+    case ICMP6_ERR_UNREACH_PORT:\r
+      return EFI_PORT_UNREACHABLE;\r
+\r
+    case ICMP6_ERR_PACKAGE_TOOBIG:\r
+    case ICMP6_ERR_PARAMPROB_HEADER:\r
+    case ICMP6_ERR_PARAMPROB_NEXHEADER:\r
+    case ICMP6_ERR_PARAMPROB_IPV6OPTION:\r
+      return EFI_ICMP_ERROR;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // Should never be here\r
+    //\r
+    ASSERT (FALSE);\r
+    return EFI_UNSUPPORTED;\r
   }\r
+}\r
 \r
-  switch (IcmpError) {\r
-  case ICMP_ERR_UNREACH_NET:\r
-    return  EFI_NETWORK_UNREACHABLE;\r
 \r
-  case ICMP_ERR_TIMXCEED_INTRANS:\r
-  case ICMP_ERR_TIMXCEED_REASS:\r
-  case ICMP_ERR_UNREACH_HOST:\r
-    return  EFI_HOST_UNREACHABLE;\r
+/**\r
+  Refresh the remote peer's Neighbor Cache entries.\r
+\r
+  This function is called when the caller needs the IpIo to refresh the existing\r
+  IPv6 neighbor cache entries since the neighbor is considered reachable by the\r
+  node has recently received a confirmation that packets sent recently to the\r
+  neighbor were received by its IP layer.\r
+\r
+  @param[in]   IpIo                  Pointer to an IP_IO instance\r
+  @param[in]   Neighbor              The IP address of the neighbor\r
+  @param[in]   Timeout               Time in 100-ns units that this entry will\r
+                                     remain in the neighbor cache. A value of\r
+                                     zero means that the entry is permanent.\r
+                                     A value of non-zero means that the entry is\r
+                                     dynamic and will be deleted after Timeout.\r
+\r
+  @retval      EFI_SUCCESS           The operation is completed successfully.\r
+  @retval      EFI_NOT_STARTED       The IpIo is not configured.\r
+  @retval      EFI_INVALID_PARAMETER Neighbor Address is invalid.\r
+  @retval      EFI_NOT_FOUND         The neighbor cache entry is not in the\r
+                                     neighbor table.\r
+  @retval      EFI_UNSUPPORTED       IP version is IPv4, which doesn't support neighbor cache refresh.\r
+  @retval      EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
 \r
-  case ICMP_ERR_UNREACH_PROTOCOL:\r
-    return  EFI_PROTOCOL_UNREACHABLE;\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IpIoRefreshNeighbor (\r
+  IN IP_IO           *IpIo,\r
+  IN EFI_IP_ADDRESS  *Neighbor,\r
+  IN UINT32          Timeout\r
+  )\r
+{\r
+  EFI_IP6_PROTOCOL  *Ip;\r
 \r
-  case ICMP_ERR_UNREACH_PORT:\r
-    return  EFI_PORT_UNREACHABLE;\r
+  if (!IpIo->IsConfigured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
 \r
-  case ICMP_ERR_MSGSIZE:\r
-  case ICMP_ERR_UNREACH_SRCFAIL:\r
-  case ICMP_ERR_QUENCH:\r
-  case ICMP_ERR_PARAMPROB:\r
-    return  EFI_ICMP_ERROR;\r
+  if (IpIo->IpVersion != IP_VERSION_6) {\r
+    return EFI_UNSUPPORTED;\r
   }\r
 \r
-  //\r
-  // will never run here!\r
-  //\r
-  ASSERT (FALSE);\r
-  return EFI_UNSUPPORTED;\r
+  Ip = IpIo->Ip.Ip6;\r
+\r
+  return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);\r
 }\r
 \r