]> git.proxmox.com Git - mirror_edk2.git/commitdiff
NetworkPkg:Enable Http Boot over Ipv6 stack
authorZhang Lubo <lubo.zhang@intel.com>
Mon, 9 Nov 2015 03:30:42 +0000 (03:30 +0000)
committerluobozhang <luobozhang@Edk2>
Mon, 9 Nov 2015 03:30:42 +0000 (03:30 +0000)
Add new features to support Http boot over ipv6 stack.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Zhang Lubo <lubo.zhang@intel.com>
Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
Reviewed-by: Wu Jiaxin <jiaxin.wu@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18743 6f19259b-4bc3-4df7-8a09-765794883524

23 files changed:
NetworkPkg/HttpBootDxe/HttpBootClient.c
NetworkPkg/HttpBootDxe/HttpBootComponentName.c
NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
NetworkPkg/HttpBootDxe/HttpBootDhcp4.h
NetworkPkg/HttpBootDxe/HttpBootDhcp6.c [new file with mode: 0644]
NetworkPkg/HttpBootDxe/HttpBootDhcp6.h [new file with mode: 0644]
NetworkPkg/HttpBootDxe/HttpBootDxe.c
NetworkPkg/HttpBootDxe/HttpBootDxe.h
NetworkPkg/HttpBootDxe/HttpBootDxe.inf
NetworkPkg/HttpBootDxe/HttpBootDxe.uni
NetworkPkg/HttpBootDxe/HttpBootImpl.c
NetworkPkg/HttpBootDxe/HttpBootImpl.h
NetworkPkg/HttpBootDxe/HttpBootSupport.c
NetworkPkg/HttpBootDxe/HttpBootSupport.h
NetworkPkg/HttpDxe/HttpDns.c
NetworkPkg/HttpDxe/HttpDns.h
NetworkPkg/HttpDxe/HttpDriver.c
NetworkPkg/HttpDxe/HttpDriver.h
NetworkPkg/HttpDxe/HttpDxe.inf
NetworkPkg/HttpDxe/HttpDxe.uni
NetworkPkg/HttpDxe/HttpImpl.c
NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg/HttpDxe/HttpProto.h

index 5669c5f37ce1f511879fe117d34f8420cf2a12d3..b81b03c96070400db493e148f53ebfcb1e4cb2a4 100644 (file)
@@ -54,14 +54,27 @@ HttpBootUpdateDevicePath (
     Node->Ipv4.StaticIpAddress = FALSE;\r
     CopyMem (&Node->Ipv4.GatewayIpAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
     CopyMem (&Node->Ipv4.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
-    \r
-    TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
-    FreePool (Node);\r
-    if (TmpDevicePath == NULL) {\r
+  } else {\r
+    Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));\r
+    if (Node == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
-  } else {\r
-    ASSERT (FALSE);\r
+    Node->Ipv6.Header.Type     = MESSAGING_DEVICE_PATH;\r
+    Node->Ipv6.Header.SubType  = MSG_IPv6_DP;\r
+    SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));\r
+    Node->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;\r
+    Node->Ipv6.RemotePort      = Private->Port;\r
+    Node->Ipv6.Protocol        = EFI_IP_PROTO_TCP; \r
+    Node->Ipv6.IpAddressOrigin = 0;\r
+    CopyMem (&Node->Ipv6.LocalIpAddress, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+    CopyMem (&Node->Ipv6.RemoteIpAddress, &Private->ServerIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+    CopyMem (&Node->Ipv6.GatewayIpAddress, &Private->GatewayIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+  }\r
+  \r
+  TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+  FreePool (Node);\r
+  if (TmpDevicePath == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   //\r
@@ -85,21 +98,39 @@ HttpBootUpdateDevicePath (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  //\r
-  // Reinstall the device path protocol of the child handle.\r
-  //\r
-  Status = gBS->ReinstallProtocolInterface (\r
-                  Private->ChildHandle,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  Private->DevicePath,\r
-                  NewDevicePath\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if (!Private->UsingIpv6) {\r
+    //\r
+    // Reinstall the device path protocol of the child handle.\r
+    //\r
+    Status = gBS->ReinstallProtocolInterface (\r
+                    Private->Ip4Nic->Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Private->Ip4Nic->DevicePath,\r
+                    NewDevicePath\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    FreePool (Private->Ip4Nic->DevicePath);\r
+    Private->Ip4Nic->DevicePath = NewDevicePath;\r
+  } else {\r
+    //\r
+    // Reinstall the device path protocol of the child handle.\r
+    //\r
+    Status = gBS->ReinstallProtocolInterface (\r
+                    Private->Ip6Nic->Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Private->Ip6Nic->DevicePath,\r
+                    NewDevicePath\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    FreePool (Private->Ip6Nic->DevicePath);\r
+    Private->Ip6Nic->DevicePath = NewDevicePath;\r
   }\r
   \r
-  FreePool (Private->DevicePath);\r
-  Private->DevicePath = NewDevicePath;\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -113,7 +144,7 @@ HttpBootUpdateDevicePath (
 \r
 **/\r
 EFI_STATUS\r
-HttpBootExtractUriInfo (\r
+HttpBootDhcp4ExtractUriInfo (\r
   IN     HTTP_BOOT_PRIVATE_DATA   *Private\r
   )\r
 {\r
@@ -192,6 +223,159 @@ HttpBootExtractUriInfo (
   return Status;\r
 }\r
 \r
+/**\r
+  Parse the boot file URI information from the selected Dhcp6 offer packet.\r
+\r
+  @param[in]    Private        The pointer to the driver's private data.\r
+\r
+  @retval EFI_SUCCESS          Successfully parsed out all the boot information.\r
+  @retval Others               Failed to parse out the boot information.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootDhcp6ExtractUriInfo (\r
+  IN     HTTP_BOOT_PRIVATE_DATA   *Private\r
+  )\r
+{\r
+  HTTP_BOOT_DHCP6_PACKET_CACHE    *SelectOffer;\r
+  HTTP_BOOT_DHCP6_PACKET_CACHE    *HttpOffer;\r
+  UINT32                          SelectIndex;\r
+  UINT32                          ProxyIndex;\r
+  EFI_DHCP6_PACKET_OPTION         *Option;\r
+  EFI_IPv6_ADDRESS                IpAddr;\r
+  CHAR8                           *HostName;\r
+  CHAR16                          *HostNameStr;\r
+  EFI_STATUS                      Status;\r
+\r
+  ASSERT (Private != NULL);\r
+  ASSERT (Private->SelectIndex != 0);\r
+  SelectIndex = Private->SelectIndex - 1;\r
+  ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);\r
+\r
+  Status   = EFI_SUCCESS;\r
+  HostName = NULL;\r
+  //\r
+  // SelectOffer contains the IP address configuration and name server configuration.\r
+  // HttpOffer contains the boot file URL.\r
+  //\r
+  SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
+  if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {\r
+    HttpOffer = SelectOffer;\r
+  } else {\r
+    ASSERT (Private->SelectProxyType != HttpOfferTypeMax);\r
+    ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
+    HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;\r
+  }\r
+\r
+  //\r
+  //  Set the Local station address to IP layer.\r
+  //\r
+  Status = HttpBootSetIp6Address (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Configure the default DNS server if server assigned.\r
+  //\r
+  if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {\r
+    Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];\r
+    ASSERT (Option != NULL);\r
+    Status = HttpBootSetIp6Dns (\r
+               Private,\r
+               HTONS (Option->OpLen),\r
+               Option->Data\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Extract the HTTP server Ip frome URL. This is used to Check route table \r
+  // whether can send message to HTTP Server Ip through the GateWay.\r
+  //\r
+  Status = HttpUrlGetIp6 (\r
+             (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+             HttpOffer->UriParser,\r
+             &IpAddr\r
+             );\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The Http server address is expressed by Name Ip, so perform DNS resolution\r
+    //\r
+    Status = HttpUrlGetHostName (\r
+               (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+               HttpOffer->UriParser,\r
+               &HostName\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
+    if (HostNameStr == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+    \r
+    AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+    Status = HttpBootDns (Private, HostNameStr, &IpAddr);\r
+    FreePool (HostNameStr);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }  \r
+  } \r
+  \r
+  CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS));  \r
+    \r
+  //\r
+  // register the IPv6 gateway address to the network device.\r
+  //\r
+  Status = HttpBootSetIp6Gateway (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Extract the port from URL, and use default HTTP port 80 if not provided.\r
+  //\r
+  Status = HttpUrlGetPort (\r
+             (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+             HttpOffer->UriParser,\r
+             &Private->Port\r
+             );\r
+  if (EFI_ERROR (Status) || Private->Port == 0) {\r
+    Private->Port = 80;\r
+  }\r
+  \r
+  //\r
+  // Record the URI of boot file from the selected HTTP offer.\r
+  //\r
+  Private->BootFileUriParser = HttpOffer->UriParser;\r
+  Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data;\r
+\r
+  \r
+  //\r
+  // All boot informations are valid here.\r
+  //\r
+  AsciiPrint ("\n  URI: %a", Private->BootFileUri);\r
+  //\r
+  // Update the device path to include the IP and boot URI information.\r
+  //\r
+  Status = HttpBootUpdateDevicePath (Private);\r
+\r
+Error:\r
+  \r
+  if (HostName != NULL) {\r
+    FreePool (HostName);\r
+  }\r
+    \r
+  return Status;\r
+}\r
+\r
+\r
 /**\r
   Discover all the boot information for boot file.\r
 \r
@@ -218,9 +402,9 @@ HttpBootDiscoverBootInfo (
   }\r
 \r
   if (!Private->UsingIpv6) {\r
-    Status = HttpBootExtractUriInfo (Private);\r
+    Status = HttpBootDhcp4ExtractUriInfo (Private);\r
   } else {\r
-    ASSERT (FALSE);\r
+    Status = HttpBootDhcp6ExtractUriInfo (Private);\r
   }\r
 \r
   return Status;\r
@@ -247,12 +431,14 @@ HttpBootCreateHttpIo (
 \r
   ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));\r
   if (!Private->UsingIpv6) {\r
-    ConfigData.Config4.HttpVersion = HttpVersion11;\r
+    ConfigData.Config4.HttpVersion    = HttpVersion11;\r
     ConfigData.Config4.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
     IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4);\r
     IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4);\r
   } else {\r
-    ASSERT (FALSE);\r
+    ConfigData.Config6.HttpVersion    = HttpVersion11;\r
+    ConfigData.Config6.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
+    IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);\r
   }\r
 \r
   Status = HttpIoCreateIo (\r
index 0708598c4faf48592d39c73b133fbb8dfd2a60d5..2c39089da3f7bb8912649798a07f2a1c2045918f 100644 (file)
@@ -151,7 +151,10 @@ HttpBootDxeComponentNameGetControllerName (
   \r
   NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);\r
   if (NicHandle == NULL) {\r
-    return EFI_UNSUPPORTED;\r
+    NicHandle = HttpBootGetNicByIp6Children(ControllerHandle);\r
+    if (NicHandle == NULL) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
   }\r
 \r
   //\r
index 217c60823370d2e6c93f9de244bc815d8682a10e..9a947a6ea63ca1ac36aa671c8c47ee922e0da74f 100644 (file)
@@ -319,7 +319,7 @@ HttpBootParseDhcp4Packet (
   }\r
 \r
   //\r
-  // The offer with "HttpClient" is a Http offer.\r
+  // The offer with "HTTPClient" is a Http offer.\r
   //\r
   Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];\r
   if ((Option != NULL) && (Option->Length >= 9) &&\r
@@ -461,13 +461,13 @@ HttpBootCacheDhcp4Offer (
 }\r
 \r
 /**\r
-  Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.\r
+  Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
 \r
   @param[in]  Private             Pointer to HTTP boot driver private data.\r
 \r
 **/\r
 VOID\r
-HttpBootSelectDhcp4Offer (\r
+HttpBootSelectDhcpOffer (\r
   IN HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
@@ -590,7 +590,7 @@ HttpBootDhcp4CallBack (
     // Select offer according to the priority in UEFI spec, and record the SelectIndex \r
     // and SelectProxyType.\r
     //\r
-    HttpBootSelectDhcp4Offer (Private);\r
+    HttpBootSelectDhcpOffer (Private);\r
 \r
     if (Private->SelectIndex == 0) {\r
       Status = EFI_ABORTED;\r
@@ -689,7 +689,7 @@ HttpBootRegisterIp4Dns (
 \r
 **/\r
 EFI_STATUS\r
-HttpBootSetIpPolicy (\r
+HttpBootSetIp4Policy (\r
   IN HTTP_BOOT_PRIVATE_DATA         *Private\r
   )\r
 {\r
@@ -752,7 +752,7 @@ HttpBootDhcp4Dora (
   Dhcp4 = Private->Dhcp4;\r
   ASSERT (Dhcp4 != NULL);\r
 \r
-  Status = HttpBootSetIpPolicy (Private);\r
+  Status = HttpBootSetIp4Policy (Private);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
index 200501666b2ac9c36b53362e03c0471bdeb842ea..2bc46deafd41b2d3189e41ddb420d8f4aa9c720a 100644 (file)
@@ -245,6 +245,17 @@ typedef struct {
   EFI_DHCP4_PACKET_OPTION     *OptList[HTTP_BOOT_DHCP4_TAG_INDEX_MAX];\r
 } HTTP_BOOT_DHCP4_PACKET_CACHE;\r
 \r
+/**\r
+  Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
+\r
+  @param[in]  Private             Pointer to HTTP boot driver private data.\r
+\r
+**/\r
+VOID\r
+HttpBootSelectDhcpOffer (\r
+  IN HTTP_BOOT_PRIVATE_DATA  *Private\r
+  );\r
+\r
 /**\r
   Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
 \r
diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c
new file mode 100644 (file)
index 0000000..e5cf894
--- /dev/null
@@ -0,0 +1,984 @@
+/** @file\r
+  Functions implementation related with DHCPv6 for HTTP boot driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+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
+**/\r
+\r
+#include "HttpBootDxe.h"\r
+\r
+/**\r
+  Build the options buffer for the DHCPv6 request packet.\r
+\r
+  @param[in]  Private             The pointer to HTTP BOOT driver private data.\r
+  @param[out] OptList             The pointer to the option pointer array.\r
+  @param[in]  Buffer              The pointer to the buffer to contain the option list.\r
+\r
+  @return     Index               The count of the built-in options.\r
+\r
+**/\r
+UINT32\r
+HttpBootBuildDhcp6Options (\r
+  IN  HTTP_BOOT_PRIVATE_DATA       *Private,\r
+  OUT EFI_DHCP6_PACKET_OPTION      **OptList,\r
+  IN  UINT8                        *Buffer\r
+  )\r
+{\r
+  HTTP_BOOT_DHCP6_OPTION_ENTRY     OptEnt;\r
+  UINT16                           Value;\r
+  UINT32                           Index;\r
+\r
+  Index      = 0;\r
+  OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer;\r
+\r
+  //\r
+  // Append client option request option\r
+  //\r
+  OptList[Index]->OpCode     = HTONS (HTTP_BOOT_DHCP6_OPT_ORO);\r
+  OptList[Index]->OpLen      = HTONS (8);\r
+  OptEnt.Oro                 = (HTTP_BOOT_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
+  OptEnt.Oro->OpCode[0]      = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL);\r
+  OptEnt.Oro->OpCode[1]      = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM);\r
+  OptEnt.Oro->OpCode[2]      = HTONS(HTTP_BOOT_DHCP6_OPT_DNS_SERVERS);\r
+  OptEnt.Oro->OpCode[3]      = HTONS(HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS);\r
+  Index++;\r
+  OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
+\r
+  //\r
+  // Append client network device interface option\r
+  //\r
+  OptList[Index]->OpCode     = HTONS (HTTP_BOOT_DHCP6_OPT_UNDI);\r
+  OptList[Index]->OpLen      = HTONS ((UINT16)3);\r
+  OptEnt.Undi                = (HTTP_BOOT_DHCP6_OPTION_UNDI *) OptList[Index]->Data;\r
+\r
+  if (Private->Nii != NULL) {\r
+    OptEnt.Undi->Type        = Private->Nii->Type;\r
+    OptEnt.Undi->MajorVer    = Private->Nii->MajorVer;\r
+    OptEnt.Undi->MinorVer    = Private->Nii->MinorVer;\r
+  } else {\r
+    OptEnt.Undi->Type        = DEFAULT_UNDI_TYPE;\r
+    OptEnt.Undi->MajorVer    = DEFAULT_UNDI_MAJOR;\r
+    OptEnt.Undi->MinorVer    = DEFAULT_UNDI_MINOR;\r
+  }\r
+\r
+  Index++;\r
+  OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
+\r
+  //\r
+  // Append client system architecture option\r
+  //\r
+  OptList[Index]->OpCode     = HTONS (HTTP_BOOT_DHCP6_OPT_ARCH);\r
+  OptList[Index]->OpLen      = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH));\r
+  OptEnt.Arch                = (HTTP_BOOT_DHCP6_OPTION_ARCH *) OptList[Index]->Data;\r
+  Value                      = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);\r
+  CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
+  Index++;\r
+  OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
+\r
+  //\r
+  // Append vendor class identify option.\r
+  //\r
+  OptList[Index]->OpCode       = HTONS (HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS);\r
+  OptList[Index]->OpLen        = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS));\r
+  OptEnt.VendorClass           = (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data;\r
+  OptEnt.VendorClass->Vendor   = HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM);\r
+  OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (HTTP_BOOT_CLASS_ID));\r
+  CopyMem (\r
+    &OptEnt.VendorClass->ClassId,\r
+    DEFAULT_CLASS_ID_DATA,\r
+    sizeof (HTTP_BOOT_CLASS_ID)\r
+    );\r
+  HttpBootUintnToAscDecWithFormat (\r
+    EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,\r
+    OptEnt.VendorClass->ClassId.ArchitectureType,\r
+    sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)\r
+    );\r
+\r
+  if (Private->Nii != NULL) {\r
+    CopyMem (\r
+      OptEnt.VendorClass->ClassId.InterfaceName,\r
+      Private->Nii->StringId,\r
+      sizeof (OptEnt.VendorClass->ClassId.InterfaceName)\r
+      );\r
+    HttpBootUintnToAscDecWithFormat (\r
+      Private->Nii->MajorVer,\r
+      OptEnt.VendorClass->ClassId.UndiMajor,\r
+      sizeof (OptEnt.VendorClass->ClassId.UndiMajor)\r
+      );\r
+    HttpBootUintnToAscDecWithFormat (\r
+      Private->Nii->MinorVer,\r
+      OptEnt.VendorClass->ClassId.UndiMinor,\r
+      sizeof (OptEnt.VendorClass->ClassId.UndiMinor)\r
+      );\r
+  }\r
+\r
+  Index++;\r
+\r
+  return Index;\r
+}\r
+\r
+/**\r
+  Parse out a DHCPv6 option by OptTag, and find the position in buffer.\r
+\r
+  @param[in]  Buffer        The pointer to the option buffer.\r
+  @param[in]  Length        Length of the option buffer.\r
+  @param[in]  OptTag        The required option tag.\r
+\r
+  @retval     NULL          Failed to parse the required option.\r
+  @retval     Others        The postion of the required option in buffer.\r
+\r
+**/\r
+EFI_DHCP6_PACKET_OPTION *\r
+HttpBootParseDhcp6Options (\r
+  IN UINT8                       *Buffer,\r
+  IN UINT32                      Length,\r
+  IN UINT16                      OptTag\r
+  )\r
+{\r
+  EFI_DHCP6_PACKET_OPTION        *Option;\r
+  UINT32                         Offset;\r
+\r
+  Option  = (EFI_DHCP6_PACKET_OPTION *) Buffer;\r
+  Offset  = 0;\r
+\r
+  //\r
+  // OpLen and OpCode here are both stored in network order.\r
+  //\r
+  while (Offset < Length) {\r
+\r
+    if (NTOHS (Option->OpCode) == OptTag) {\r
+\r
+      return Option;\r
+    }\r
+\r
+    Offset += (NTOHS(Option->OpLen) + 4);\r
+    Option  = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset);\r
+  }\r
+\r
+  return NULL;\r
+\r
+}\r
+\r
+/**\r
+  Parse the cached DHCPv6 packet, including all the options.\r
+\r
+  @param[in]  Cache6           The pointer to a cached DHCPv6 packet.\r
+\r
+  @retval     EFI_SUCCESS      Parsed the DHCPv6 packet successfully.\r
+  @retval     EFI_DEVICE_ERROR Failed to parse and invalid the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootParseDhcp6Packet (\r
+  IN  HTTP_BOOT_DHCP6_PACKET_CACHE    *Cache6\r
+  )\r
+{\r
+  EFI_DHCP6_PACKET               *Offer;\r
+  EFI_DHCP6_PACKET_OPTION        **Options;\r
+  EFI_DHCP6_PACKET_OPTION        *Option;\r
+  HTTP_BOOT_OFFER_TYPE           OfferType;\r
+  EFI_IPv6_ADDRESS               IpAddr;\r
+  BOOLEAN                        IsProxyOffer;\r
+  BOOLEAN                        IsHttpOffer;\r
+  BOOLEAN                        IsDnsOffer;\r
+  BOOLEAN                        IpExpressedUri;\r
+  EFI_STATUS                     Status;\r
+  UINT32                         Offset;\r
+  UINT32                         Length;\r
+  \r
+  IsDnsOffer     = FALSE;\r
+  IpExpressedUri = FALSE;\r
+  IsProxyOffer   = TRUE;\r
+  IsHttpOffer    = FALSE;\r
+  Offer        = &Cache6->Packet.Offer;\r
+  Options      = Cache6->OptList;\r
+  \r
+  ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));\r
+\r
+  Option  = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option);\r
+  Offset  = 0;\r
+  Length  = GET_DHCP6_OPTION_SIZE (Offer);\r
+\r
+  //\r
+  // OpLen and OpCode here are both stored in network order, since they are from original packet.\r
+  //\r
+  while (Offset < Length) {\r
+\r
+    if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_IA_NA) {\r
+      Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option;\r
+    } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL) {\r
+      //\r
+      // The server sends this option to inform the client about an URL to a boot file.\r
+      //\r
+      Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] = Option;\r
+    } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM) {\r
+      Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
+    } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS) {\r
+      Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option;\r
+    } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_DNS_SERVERS) {\r
+      Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER] = Option;\r
+    }\r
+\r
+    Offset += (NTOHS (Option->OpLen) + 4);\r
+    Option  = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset);\r
+  }\r
+  //\r
+  // The offer with assigned client address is NOT a proxy offer.\r
+  // An ia_na option, embeded with valid ia_addr option and a status_code of success.\r
+  //\r
+  Option = Options[HTTP_BOOT_DHCP6_IDX_IA_NA];\r
+  if (Option != NULL) {\r
+    Option = HttpBootParseDhcp6Options (\r
+               Option->Data + 12,\r
+               NTOHS (Option->OpLen),\r
+               HTTP_BOOT_DHCP6_OPT_STATUS_CODE\r
+               );\r
+    if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) {\r
+      IsProxyOffer = FALSE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The offer with "HTTPClient" is a Http offer.\r
+  //\r
+  Option = Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS];\r
+\r
+  if (Option != NULL &&\r
+      NTOHS(Option->OpLen) >= 10 &&\r
+      CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 0) {\r
+      IsHttpOffer = TRUE;\r
+  }\r
+\r
+  //\r
+  // The offer with Domain Server is a DNS offer.\r
+  //\r
+  Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];\r
+  if (Option != NULL) {\r
+    IsDnsOffer = TRUE;\r
+  }\r
+\r
+  //\r
+  // Http offer must have a boot URI.\r
+  //\r
+  if (IsHttpOffer && Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
\r
+  //\r
+  // Try to retrieve the IP of HTTP server from URI. \r
+  //\r
+  if (IsHttpOffer) {\r
+    Status = HttpParseUrl (\r
+               (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+               (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
+               FALSE,\r
+               &Cache6->UriParser\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Status = HttpUrlGetIp6 (\r
+               (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+               Cache6->UriParser,\r
+               &IpAddr\r
+               );\r
+    IpExpressedUri = !EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Determine offer type of the DHCPv6 packet.\r
+  //\r
+  if (IsHttpOffer) {\r
+    if (IpExpressedUri) {\r
+      OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri;\r
+    } else {\r
+      if (!IsProxyOffer) {\r
+        OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
+      } else {\r
+        OfferType = HttpOfferTypeProxyNameUri;\r
+      }\r
+    }\r
+\r
+  } else {\r
+    if (!IsProxyOffer) {\r
+      OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
+    } else {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  \r
+  Cache6->OfferType = OfferType;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Cache the DHCPv6 packet.\r
+\r
+  @param[in]  Dst          The pointer to the cache buffer for DHCPv6 packet.\r
+  @param[in]  Src          The pointer to the DHCPv6 packet to be cached.\r
+\r
+**/\r
+VOID\r
+HttpBootCacheDhcp6Packet (\r
+  IN EFI_DHCP6_PACKET          *Dst,\r
+  IN EFI_DHCP6_PACKET          *Src\r
+  )\r
+{\r
+  ASSERT (Dst->Size >= Src->Length);\r
+\r
+  CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
+  Dst->Length = Src->Length;\r
+}\r
+\r
+/**\r
+  Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.\r
+\r
+  @param[in]  Private               The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+  @param[in]  RcvdOffer             The pointer to the received offer packet.\r
+\r
+**/\r
+VOID\r
+HttpBootCacheDhcp6Offer (\r
+  IN HTTP_BOOT_PRIVATE_DATA  *Private,\r
+  IN EFI_DHCP6_PACKET        *RcvdOffer\r
+  )\r
+{\r
+  HTTP_BOOT_DHCP6_PACKET_CACHE   *Cache6;\r
+  EFI_DHCP6_PACKET               *Offer;\r
+  HTTP_BOOT_OFFER_TYPE           OfferType;\r
+\r
+  Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
+  Offer  = &Cache6->Packet.Offer;\r
+\r
+  //\r
+  // Cache the content of DHCPv6 packet firstly.\r
+  //\r
+  HttpBootCacheDhcp6Packet(Offer, RcvdOffer);\r
+\r
+  //\r
+  // Validate the DHCPv6 packet, and parse the options and offer type.\r
+  //\r
+  if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
+  //\r
+  OfferType = Cache6->OfferType;\r
+  ASSERT (OfferType < HttpOfferTypeMax);\r
+  ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
+  Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
+  Private->OfferCount[OfferType]++;\r
+  Private->OfferNum++;  \r
+}\r
+\r
+/**\r
+  EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver\r
+  to intercept events that occurred in the configuration process.\r
+\r
+  @param[in]  This              The pointer to the EFI DHCPv6 Protocol.\r
+  @param[in]  Context           The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().\r
+  @param[in]  CurrentState      The current operational state of the EFI DHCPv Protocol driver.\r
+  @param[in]  Dhcp6Event        The event that occurs in the current state, which usually means a\r
+                                state transition.\r
+  @param[in]  Packet            The DHCPv6 packet that is going to be sent or was already received.\r
+  @param[out] NewPacket         The packet that is used to replace the Packet above.\r
+\r
+  @retval EFI_SUCCESS           Told the EFI DHCPv6 Protocol driver to continue the DHCP process.\r
+  @retval EFI_NOT_READY         Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol\r
+                                driver will continue to wait for more packets.\r
+  @retval EFI_ABORTED           Told the EFI DHCPv6 Protocol driver to abort the current process.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootDhcp6CallBack (\r
+  IN  EFI_DHCP6_PROTOCOL           *This,\r
+  IN  VOID                         *Context,\r
+  IN  EFI_DHCP6_STATE              CurrentState,\r
+  IN  EFI_DHCP6_EVENT              Dhcp6Event,\r
+  IN  EFI_DHCP6_PACKET             *Packet,\r
+  OUT EFI_DHCP6_PACKET             **NewPacket     OPTIONAL\r
+  )\r
+{\r
+   HTTP_BOOT_PRIVATE_DATA          *Private;\r
+   EFI_DHCP6_PACKET                *SelectAd;\r
+   EFI_STATUS                      Status;\r
+   if ((Dhcp6Event != Dhcp6RcvdAdvertise) && (Dhcp6Event != Dhcp6SelectAdvertise)) {\r
+     return EFI_SUCCESS;\r
+   }\r
+\r
+   ASSERT (Packet != NULL);\r
+   \r
+   Private     = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
+   Status = EFI_SUCCESS;\r
+   switch (Dhcp6Event) {\r
+    \r
+   case Dhcp6RcvdAdvertise:\r
+     Status = EFI_NOT_READY;\r
+     if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
+       //\r
+       // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
+       // the OfferIndex and OfferCount.\r
+       //\r
+       HttpBootCacheDhcp6Offer (Private, Packet);\r
+     }\r
+     break;\r
+\r
+   case Dhcp6SelectAdvertise:\r
+     //\r
+     // Select offer by the default policy or by order, and record the SelectIndex\r
+     // and SelectProxyType.\r
+     //\r
+     HttpBootSelectDhcpOffer (Private);\r
+\r
+     if (Private->SelectIndex == 0) {\r
+       Status = EFI_ABORTED;\r
+     } else {\r
+       ASSERT (NewPacket != NULL);\r
+       SelectAd   = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
+       *NewPacket = AllocateZeroPool (SelectAd->Size);\r
+       ASSERT (*NewPacket != NULL);\r
+       CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
+     }\r
+     break;\r
+     \r
+   default:\r
+     break;\r
+  }\r
+\r
+  return Status;   \r
+}\r
+\r
+/**\r
+  Check whether IP driver could route the message which will be sent to ServerIp address.\r
+  \r
+  This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid\r
+  route is found in IP6 route table, the address will be filed in GatewayAddr and return.\r
+\r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+  @param[in]  TimeOutInSecond     Timeout value in seconds.\r
+  @param[out] GatewayAddr         Pointer to store the gateway IP address.\r
+\r
+  @retval     EFI_SUCCESS         Found a valid gateway address successfully.\r
+  @retval     EFI_TIMEOUT         The operation is time out.\r
+  @retval     Other               Unexpect error happened.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpBootCheckRouteTable (\r
+  IN  HTTP_BOOT_PRIVATE_DATA        *Private,\r
+  IN  UINTN                         TimeOutInSecond,\r
+  OUT EFI_IPv6_ADDRESS              *GatewayAddr\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_IP6_PROTOCOL                 *Ip6;\r
+  EFI_IP6_MODE_DATA                Ip6ModeData;\r
+  UINTN                            Index;\r
+  EFI_EVENT                        TimeOutEvt;\r
+  UINTN                            RetryCount;\r
+  BOOLEAN                          GatewayIsFound;\r
+\r
+  ASSERT (GatewayAddr != NULL);\r
+  ASSERT (Private != NULL);\r
+\r
+  Ip6            = Private->Ip6;\r
+  GatewayIsFound = FALSE;\r
+  RetryCount     = 0;\r
+  TimeOutEvt     = NULL;\r
+  Status         = EFI_SUCCESS;\r
+  ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));\r
+\r
+  while (TRUE) {\r
+    Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    //\r
+    // Find out the gateway address which can route the message which send to ServerIp.\r
+    //\r
+    for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {\r
+      if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {\r
+        IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);\r
+        GatewayIsFound = TRUE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Ip6ModeData.AddressList != NULL) {\r
+      FreePool (Ip6ModeData.AddressList);\r
+    }\r
+    if (Ip6ModeData.GroupTable != NULL) {\r
+      FreePool (Ip6ModeData.GroupTable);\r
+    }\r
+    if (Ip6ModeData.RouteTable != NULL) {\r
+      FreePool (Ip6ModeData.RouteTable);\r
+    }\r
+    if (Ip6ModeData.NeighborCache != NULL) {\r
+      FreePool (Ip6ModeData.NeighborCache);\r
+    }\r
+    if (Ip6ModeData.PrefixTable != NULL) {\r
+      FreePool (Ip6ModeData.PrefixTable);\r
+    }\r
+    if (Ip6ModeData.IcmpTypeList != NULL) {\r
+      FreePool (Ip6ModeData.IcmpTypeList);\r
+    }\r
+    \r
+    if (GatewayIsFound || RetryCount == TimeOutInSecond) {\r
+      break;\r
+    }\r
+    \r
+    RetryCount++;\r
+    \r
+    //\r
+    // Delay 1 second then recheck it again.\r
+    //\r
+    if (TimeOutEvt == NULL) {\r
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &TimeOutEvt\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+\r
+    Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+    while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
+      Ip6->Poll (Ip6);\r
+    }\r
+  }\r
+  \r
+ON_EXIT:\r
+  if (TimeOutEvt != NULL) {\r
+    gBS->CloseEvent (TimeOutEvt);\r
+  }\r
+  \r
+  if (GatewayIsFound) {\r
+    Status = EFI_SUCCESS;\r
+  } else if (RetryCount == TimeOutInSecond) {\r
+    Status = EFI_TIMEOUT;\r
+  }\r
+\r
+  return Status; \r
+}\r
+\r
+/**\r
+  Set the IP6 policy to Automatic.\r
+\r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         Switch the IP policy succesfully.\r
+  @retval     Others              Unexpect error happened.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Policy (\r
+  IN HTTP_BOOT_PRIVATE_DATA        *Private\r
+  )\r
+{\r
+  EFI_IP6_CONFIG_POLICY            Policy;\r
+  EFI_IP6_CONFIG_PROTOCOL          *Ip6Config;\r
+  EFI_STATUS                       Status;\r
+  UINTN                            DataSize;\r
+\r
+  Ip6Config       = Private->Ip6Config;\r
+  DataSize        = sizeof (EFI_IP6_CONFIG_POLICY);\r
+  \r
+  //\r
+  // Get and store the current policy of IP6 driver.\r
+  //\r
+  Status = Ip6Config->GetData (\r
+                        Ip6Config,\r
+                        Ip6ConfigDataTypePolicy,\r
+                        &DataSize,\r
+                        &Policy\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Policy == Ip6ConfigPolicyManual) {\r
+    Policy = Ip6ConfigPolicyAutomatic;\r
+    Status = Ip6Config->SetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypePolicy,\r
+                          sizeof(EFI_IP6_CONFIG_POLICY),\r
+                          &Policy\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function will register the default DNS addresses to the network device.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+  @param[in]  DataLength          Size of the buffer pointed to by DnsServerData in bytes.\r
+  @param[in]  DnsServerData       Point a list of DNS server address in an array\r
+                                  of EFI_IPv6_ADDRESS instances.\r
+\r
+  @retval     EFI_SUCCESS         The DNS configuration has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Dns (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private,\r
+  IN UINTN                          DataLength,\r
+  IN VOID                           *DnsServerData\r
+  )\r
+{\r
+  EFI_IP6_CONFIG_PROTOCOL        *Ip6Config;\r
+  \r
+  ASSERT (Private->UsingIpv6);\r
+\r
+  Ip6Config = Private->Ip6Config;\r
+  \r
+  return Ip6Config->SetData (\r
+                      Ip6Config,\r
+                      Ip6ConfigDataTypeDnsServer,\r
+                      DataLength,\r
+                      DnsServerData\r
+                      );\r
+}\r
+\r
+/**\r
+  This function will register the IPv6 gateway address to the network device.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         The new IP configuration has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Gateway (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+  )\r
+{\r
+  EFI_IP6_CONFIG_PROTOCOL           *Ip6Config;\r
+  EFI_STATUS                        Status;\r
+\r
+  ASSERT (Private->UsingIpv6);\r
+  Ip6Config = Private->Ip6Config;\r
\r
+  //\r
+  // Set the default gateway address. \r
+  //\r
+  if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) {\r
+    Status = Ip6Config->SetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeGateway,\r
+                          sizeof (EFI_IPv6_ADDRESS),\r
+                          &Private->GatewayIp.v6\r
+                          );\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function will register the station IP address.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         The new IP address has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Address (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+)\r
+{\r
+  EFI_STATUS                         Status;\r
+  EFI_IP6_PROTOCOL                   *Ip6;\r
+  EFI_IP6_CONFIG_PROTOCOL            *Ip6Cfg;\r
+  EFI_IP6_CONFIG_POLICY              Policy;\r
+  EFI_IP6_CONFIG_MANUAL_ADDRESS      CfgAddr;\r
+  EFI_IPv6_ADDRESS                   *Ip6Addr;\r
+  EFI_IPv6_ADDRESS                   GatewayAddr;\r
+  EFI_IP6_CONFIG_DATA                Ip6CfgData;\r
+  EFI_EVENT                          MappedEvt; \r
+  UINTN                              DataSize;\r
+  BOOLEAN                            IsAddressOk;\r
+  UINTN                              Index;\r
+\r
+  ASSERT (Private->UsingIpv6);\r
+  \r
+  MappedEvt   = NULL;\r
+  IsAddressOk = FALSE;\r
+  Ip6Addr     = NULL;\r
+  Ip6Cfg      = Private->Ip6Config;\r
+  Ip6         = Private->Ip6;\r
+  \r
+  ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
+  CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+  ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA));\r
+  \r
+  Ip6CfgData.AcceptIcmpErrors    = TRUE;\r
+  Ip6CfgData.DefaultProtocol     = IP6_ICMP;\r
+  Ip6CfgData.HopLimit            = HTTP_BOOT_DEFAULT_HOPLIMIT;\r
+  Ip6CfgData.ReceiveTimeout      = HTTP_BOOT_DEFAULT_LIFETIME;\r
+  Ip6CfgData.TransmitTimeout     = HTTP_BOOT_DEFAULT_LIFETIME;\r
+    \r
+  Status = Ip6->Configure (Ip6, &Ip6CfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Retrieve the gateway address from IP6 route table.\r
+  //\r
+  Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);\r
+  if (EFI_ERROR (Status)) {\r
+    Private->NoGateway = TRUE;\r
+  } else {\r
+    IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr);\r
+  }\r
+\r
+  //\r
+  // Set the new address by Ip6ConfigProtocol manually.\r
+  //\r
+  Policy = Ip6ConfigPolicyManual;\r
+  Status = Ip6Cfg->SetData (\r
+                     Ip6Cfg,\r
+                     Ip6ConfigDataTypePolicy,\r
+                     sizeof(EFI_IP6_CONFIG_POLICY),\r
+                     &Policy\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Create a notify event to set address flag when DAD if IP6 driver succeeded.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpBootCommonNotify,\r
+                  &IsAddressOk,\r
+                  &MappedEvt\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Set static host ip6 address. This is a asynchronous process.\r
+  //\r
+  Status = Ip6Cfg->RegisterDataNotify (\r
+                     Ip6Cfg,\r
+                     Ip6ConfigDataTypeManualAddress,\r
+                     MappedEvt\r
+                     );\r
+  if (EFI_ERROR(Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = Ip6Cfg->SetData (\r
+                     Ip6Cfg,\r
+                     Ip6ConfigDataTypeManualAddress,\r
+                     sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),\r
+                     &CfgAddr\r
+                     ); \r
+  if (EFI_ERROR (Status) && Status != EFI_NOT_READY) {\r
+    goto ON_EXIT;\r
+  } else if (Status == EFI_NOT_READY) {\r
+    //\r
+    // Poll the network until the asynchronous process is finished.\r
+    //\r
+    while (!IsAddressOk) {\r
+      Ip6->Poll (Ip6);\r
+    }\r
+    //\r
+    // Check whether the Ip6 Address setting is successed.\r
+    //\r
+    DataSize = 0;\r
+    Status = Ip6Cfg->GetData (\r
+                       Ip6Cfg,\r
+                       Ip6ConfigDataTypeManualAddress,\r
+                       &DataSize,\r
+                       NULL\r
+                       );\r
+    if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    Ip6Addr = AllocatePool (DataSize);\r
+    if (Ip6Addr == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = Ip6Cfg->GetData (\r
+                       Ip6Cfg,\r
+                       Ip6ConfigDataTypeManualAddress,\r
+                       &DataSize,\r
+                       (VOID *) Ip6Addr\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index ++) {\r
+      if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) {\r
+        break;\r
+      }\r
+    }\r
+    if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {\r
+      Status = EFI_ABORTED;\r
+      goto ON_EXIT;\r
+    } \r
+  }\r
+    \r
+ON_EXIT:\r
+  if (MappedEvt != NULL) {\r
+    Ip6Cfg->UnregisterDataNotify (\r
+              Ip6Cfg,\r
+              Ip6ConfigDataTypeManualAddress,\r
+              MappedEvt\r
+              );\r
+    gBS->CloseEvent (MappedEvt);\r
+  }\r
+\r
+  if (Ip6Addr != NULL) {\r
+    FreePool (Ip6Addr);\r
+  }\r
+  \r
+  return Status;    \r
+}\r
+\r
+/**\r
+  Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.\r
+\r
+  @param[in]  Private           Pointer to HTTP_BOOT private data.\r
+\r
+  @retval EFI_SUCCESS           The S.A.R.R process successfully finished.\r
+  @retval Others                Failed to finish the S.A.R.R process.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootDhcp6Sarr (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+  )\r
+{\r
+  EFI_DHCP6_PROTOCOL               *Dhcp6;\r
+  EFI_DHCP6_CONFIG_DATA            Config;\r
+  EFI_DHCP6_MODE_DATA              Mode;\r
+  EFI_DHCP6_RETRANSMISSION         *Retransmit;\r
+  EFI_DHCP6_PACKET_OPTION          *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM];\r
+  UINT32                           OptCount;\r
+  UINT8                            Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];\r
+  EFI_STATUS                       Status;\r
+\r
+  Dhcp6 = Private->Dhcp6;\r
+  ASSERT (Dhcp6 != NULL);\r
+\r
+  //\r
+  // Build options list for the request packet.\r
+  //\r
+  OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer);\r
+  ASSERT (OptCount >0);\r
+  \r
+  Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r
+  if (Retransmit == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
+  ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
+  \r
+  Config.OptionCount           = OptCount;\r
+  Config.OptionList            = OptList;\r
+  Config.Dhcp6Callback         = HttpBootDhcp6CallBack;\r
+  Config.CallbackContext       = Private;\r
+  Config.IaInfoEvent           = NULL;\r
+  Config.RapidCommit           = FALSE;\r
+  Config.ReconfigureAccept     = FALSE;\r
+  Config.IaDescriptor.IaId     = NET_RANDOM (NetRandomInitSeed ());\r
+  Config.IaDescriptor.Type     = EFI_DHCP6_IA_TYPE_NA;\r
+  Config.SolicitRetransmission = Retransmit;\r
+  Retransmit->Irt              = 4;\r
+  Retransmit->Mrc              = 4;\r
+  Retransmit->Mrt              = 32;\r
+  Retransmit->Mrd              = 60;\r
+  \r
+  //\r
+  // Configure the DHCPv6 instance for HTTP boot.\r
+  //\r
+  Status = Dhcp6->Configure (Dhcp6, &Config);\r
+  FreePool (Retransmit);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Initialize the record fields for DHCPv6 offer in private data.\r
+  //\r
+  Private->OfferNum      = 0;\r
+  Private->SelectIndex   = 0;\r
+  ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
+  ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
+  \r
+  //\r
+  // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
+  //\r
+  Status = Dhcp6->Start (Dhcp6);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Get the acquired IPv6 address and store them.\r
+  //\r
+  Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  ASSERT (Mode.Ia->State == Dhcp6Bound);\r
+  CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
+  \r
+  AsciiPrint ("\n  Station IPv6 address is ");\r
+  HttpBootShowIp6Addr (&Private->StationIp.v6);\r
+  AsciiPrint ("\n");\r
+  \r
+ON_EXIT:\r
+  if (EFI_ERROR (Status)) {\r
+    Dhcp6->Stop (Dhcp6);\r
+    Dhcp6->Configure (Dhcp6, NULL);\r
+  } else {\r
+    ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
+    ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
+    Dhcp6->Configure (Dhcp6, &Config);\r
+  }\r
+\r
+  return Status; \r
+    \r
+}\r
+\r
diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.h b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.h
new file mode 100644 (file)
index 0000000..59ca19e
--- /dev/null
@@ -0,0 +1,198 @@
+/** @file\r
+  Functions declaration related with DHCPv6 for HTTP boot driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+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
+**/\r
+\r
+\r
+#ifndef __EFI_HTTP_BOOT_DHCP6_H__\r
+#define __EFI_HTTP_BOOT_DHCP6_H__\r
+\r
+#define HTTP_BOOT_OFFER_MAX_NUM                16\r
+#define HTTP_BOOT_DHCP6_OPTION_MAX_NUM         16\r
+#define HTTP_BOOT_DHCP6_OPTION_MAX_SIZE        312\r
+#define HTTP_BOOT_DHCP6_PACKET_MAX_SIZE        1472\r
+#define HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT      10\r
+#define HTTP_BOOT_DEFAULT_HOPLIMIT             64\r
+#define HTTP_BOOT_DEFAULT_LIFETIME             50000\r
+\r
+\r
+#define HTTP_BOOT_DHCP6_OPT_CLIENT_ID         1\r
+#define HTTP_BOOT_DHCP6_OPT_SERVER_ID         2\r
+#define HTTP_BOOT_DHCP6_OPT_IA_NA             3\r
+#define HTTP_BOOT_DHCP6_OPT_IA_TA             4\r
+#define HTTP_BOOT_DHCP6_OPT_IAADDR            5\r
+#define HTTP_BOOT_DHCP6_OPT_ORO               6\r
+#define HTTP_BOOT_DHCP6_OPT_PREFERENCE        7\r
+#define HTTP_BOOT_DHCP6_OPT_ELAPSED_TIME      8\r
+#define HTTP_BOOT_DHCP6_OPT_REPLAY_MSG        9\r
+#define HTTP_BOOT_DHCP6_OPT_AUTH              11\r
+#define HTTP_BOOT_DHCP6_OPT_UNICAST           12\r
+#define HTTP_BOOT_DHCP6_OPT_STATUS_CODE       13\r
+#define HTTP_BOOT_DHCP6_OPT_RAPID_COMMIT      14\r
+#define HTTP_BOOT_DHCP6_OPT_USER_CLASS        15\r
+#define HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS      16\r
+#define HTTP_BOOT_DHCP6_OPT_VENDOR_OPTS       17\r
+#define HTTP_BOOT_DHCP6_OPT_INTERFACE_ID      18\r
+#define HTTP_BOOT_DHCP6_OPT_RECONFIG_MSG      19\r
+#define HTTP_BOOT_DHCP6_OPT_RECONFIG_ACCEPT   20\r
+#define HTTP_BOOT_DHCP6_OPT_DNS_SERVERS       23\r
+#define HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL     59    // Assigned by IANA, RFC 5970\r
+#define HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM   60    // Assigned by IANA, RFC 5970\r
+#define HTTP_BOOT_DHCP6_OPT_ARCH              61    // Assigned by IANA, RFC 5970\r
+#define HTTP_BOOT_DHCP6_OPT_UNDI              62    // Assigned by IANA, RFC 5970\r
+#define HTTP_BOOT_DHCP6_ENTERPRISE_NUM        343   // TODO: IANA TBD: temporarily using Intel's\r
+#define HTTP_BOOT_DHCP6_MAX_BOOT_FILE_SIZE    65535 //   It's a limitation of bit length, 65535*512 bytes.\r
+\r
+#define HTTP_BOOT_DHCP6_IDX_IA_NA             0\r
+#define HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL     1\r
+#define HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM   2\r
+#define HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS      3\r
+#define HTTP_BOOT_DHCP6_IDX_DNS_SERVER        4\r
+#define HTTP_BOOT_DHCP6_IDX_MAX               5\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT16 OpCode[256];\r
+} HTTP_BOOT_DHCP6_OPTION_ORO;\r
+\r
+typedef struct {\r
+  UINT8 Type;\r
+  UINT8 MajorVer;\r
+  UINT8 MinorVer;\r
+} HTTP_BOOT_DHCP6_OPTION_UNDI;\r
+\r
+typedef struct {\r
+  UINT16 Type;\r
+} HTTP_BOOT_DHCP6_OPTION_ARCH;\r
+\r
+typedef struct {\r
+  UINT8 ClassIdentifier[10];\r
+  UINT8 ArchitecturePrefix[5];\r
+  UINT8 ArchitectureType[5];\r
+  UINT8 Lit3[1];\r
+  UINT8 InterfaceName[4];\r
+  UINT8 Lit4[1];\r
+  UINT8 UndiMajor[3];\r
+  UINT8 UndiMinor[3];\r
+} HTTP_BOOT_CLASS_ID;\r
+\r
+typedef struct {\r
+  UINT32             Vendor;\r
+  UINT16             ClassLen;\r
+  HTTP_BOOT_CLASS_ID ClassId;\r
+} HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS;\r
+\r
+#pragma pack()\r
+\r
+typedef union {\r
+  HTTP_BOOT_DHCP6_OPTION_ORO            *Oro;\r
+  HTTP_BOOT_DHCP6_OPTION_UNDI           *Undi;\r
+  HTTP_BOOT_DHCP6_OPTION_ARCH           *Arch;\r
+  HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS   *VendorClass;\r
+} HTTP_BOOT_DHCP6_OPTION_ENTRY;\r
+\r
+typedef union {\r
+  EFI_DHCP6_PACKET        Offer;\r
+  EFI_DHCP6_PACKET        Ack;\r
+  UINT8                   Buffer[HTTP_BOOT_DHCP6_PACKET_MAX_SIZE];\r
+} HTTP_BOOT_DHCP6_PACKET;\r
+\r
+typedef struct {\r
+  HTTP_BOOT_DHCP6_PACKET      Packet;\r
+  HTTP_BOOT_OFFER_TYPE        OfferType;\r
+  EFI_DHCP6_PACKET_OPTION     *OptList[HTTP_BOOT_DHCP6_IDX_MAX];\r
+  VOID                        *UriParser;\r
+} HTTP_BOOT_DHCP6_PACKET_CACHE;\r
+\r
+#define GET_NEXT_DHCP6_OPTION(Opt) \\r
+  (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \\r
+  sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1)\r
+\r
+#define GET_DHCP6_OPTION_SIZE(Pkt)  \\r
+  ((Pkt)->Length - sizeof (EFI_DHCP6_HEADER))\r
+\r
+/**\r
+  Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.\r
+\r
+  @param[in]  Private           Pointer to HTTP_BOOT private data.\r
+\r
+  @retval EFI_SUCCESS           The S.A.R.R process successfully finished.\r
+  @retval Others                Failed to finish the S.A.R.R process.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootDhcp6Sarr (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+  );\r
+\r
+/**\r
+  Set the IP6 policy to Automatic.\r
+\r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         Switch the IP policy succesfully.\r
+  @retval     Others              Unexpect error happened.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Policy (\r
+  IN HTTP_BOOT_PRIVATE_DATA        *Private\r
+  );\r
+\r
+/**\r
+  This function will register the default DNS addresses to the network device.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+  @param[in]  DataLength          Size of the buffer pointed to by DnsServerData in bytes.\r
+  @param[in]  DnsServerData       Point a list of DNS server address in an array\r
+                                  of EFI_IPv6_ADDRESS instances.\r
+\r
+  @retval     EFI_SUCCESS         The DNS configuration has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Dns (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private,\r
+  IN UINTN                          DataLength,\r
+  IN VOID                           *DnsServerData\r
+  );\r
+\r
+/**\r
+  This function will register the IPv6 gateway address to the network device.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         The new IP configuration has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Gateway (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+  );\r
+\r
+/**\r
+  This function will register the station IP address.\r
+  \r
+  @param[in]  Private             The pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+  @retval     EFI_SUCCESS         The new IP address has been configured successfully.\r
+  @retval     Others              Failed to configure the address.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootSetIp6Address (\r
+  IN HTTP_BOOT_PRIVATE_DATA         *Private\r
+  );\r
+\r
+#endif\r
index 49be59b8c8e3d244f5d1b0f5cd23e24443a20555..a7fc8a8e2e634505f82035d43c47b21ec3e4d8bd 100644 (file)
@@ -26,6 +26,15 @@ EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = {
   NULL\r
 };\r
 \r
+EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp6DxeDriverBinding = {\r
+  HttpBootIp6DxeDriverBindingSupported,\r
+  HttpBootIp6DxeDriverBindingStart,\r
+  HttpBootIp6DxeDriverBindingStop,\r
+  HTTP_BOOT_DXE_VERSION,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
 /**\r
   Destroy the HTTP child based on IPv4 stack.\r
 \r
@@ -45,11 +54,11 @@ HttpBootDestroyIp4Children (
 \r
   if (Private->Dhcp4Child != NULL) {\r
     gBS->CloseProtocol (\r
-          Private->Dhcp4Child,\r
-          &gEfiDhcp4ProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Private->Controller\r
-          );\r
+           Private->Dhcp4Child,\r
+           &gEfiDhcp4ProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Private->Controller\r
+           );\r
 \r
     NetLibDestroyServiceChild (\r
       Private->Controller,\r
@@ -64,25 +73,102 @@ HttpBootDestroyIp4Children (
     Private->HttpCreated = FALSE;\r
   }\r
 \r
-  gBS->CloseProtocol (\r
-         Private->Controller,\r
-         &gEfiCallerIdGuid,\r
-         This->DriverBindingHandle,\r
-         Private->ChildHandle\r
-         );\r
+  if (Private->Ip4Nic != NULL) {\r
+    \r
+    gBS->CloseProtocol (\r
+           Private->Controller,\r
+           &gEfiCallerIdGuid,\r
+           This->DriverBindingHandle,\r
+           Private->Ip4Nic->Controller\r
+           );\r
+    \r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           Private->Ip4Nic->Controller,\r
+           &gEfiLoadFileProtocolGuid,\r
+           &Private->Ip4Nic->LoadFile,\r
+           &gEfiDevicePathProtocolGuid,\r
+           Private->Ip4Nic->DevicePath,\r
+           NULL\r
+           );\r
+    FreePool (Private->Ip4Nic);\r
+    Private->Ip4Nic = NULL;\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Destroy the HTTP child based on IPv6 stack.\r
+\r
+  @param[in]  This              Pointer to the EFI_DRIVER_BINDING_PROTOCOL.\r
+  @param[in]  Private           Pointer to HTTP_BOOT_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+HttpBootDestroyIp6Children (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN HTTP_BOOT_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  ASSERT (This != NULL);\r
+  ASSERT (Private != NULL);\r
+  ASSERT (Private->UsingIpv6 == TRUE);\r
+  \r
+  if (Private->Ip6Child != NULL) {\r
+    gBS->CloseProtocol (\r
+           Private->Ip6Child,\r
+           &gEfiIp6ProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Private->Controller\r
+           );\r
+\r
+    NetLibDestroyServiceChild (\r
+      Private->Controller,\r
+      This->DriverBindingHandle,\r
+      &gEfiIp6ServiceBindingProtocolGuid,\r
+      Private->Ip6Child\r
+      );\r
+  }\r
+\r
+  if (Private->Dhcp6Child != NULL) {\r
+    gBS->CloseProtocol (\r
+           Private->Dhcp6Child,\r
+           &gEfiDhcp6ProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Private->Controller\r
+           );\r
 \r
-  gBS->UninstallMultipleProtocolInterfaces (\r
-         Private->ChildHandle,\r
-         &gEfiLoadFileProtocolGuid,\r
-         &Private->LoadFile,\r
-         &gEfiDevicePathProtocolGuid,\r
-         Private->DevicePath,\r
-         NULL\r
-         );\r
+    NetLibDestroyServiceChild (\r
+      Private->Controller,\r
+      This->DriverBindingHandle,\r
+      &gEfiDhcp6ServiceBindingProtocolGuid,\r
+      Private->Dhcp6Child\r
+      );\r
+  }\r
 \r
-  if (Private->DevicePath != NULL) {\r
-    FreePool (Private->DevicePath);\r
-    Private->DevicePath = NULL;\r
+  if (Private->HttpCreated) {\r
+    HttpIoDestroyIo(&Private->HttpIo);\r
+    Private->HttpCreated = FALSE;\r
+  }\r
+  \r
+  if (Private->Ip6Nic != NULL) {\r
+    \r
+    gBS->CloseProtocol (\r
+           Private->Controller,\r
+           &gEfiCallerIdGuid,\r
+           This->DriverBindingHandle,\r
+           Private->Ip6Nic->Controller\r
+           );\r
+    \r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           Private->Ip6Nic->Controller,\r
+           &gEfiLoadFileProtocolGuid,\r
+           &Private->Ip6Nic->LoadFile,\r
+           &gEfiDevicePathProtocolGuid,\r
+           Private->Ip6Nic->DevicePath,\r
+           NULL\r
+           );\r
+    FreePool (Private->Ip6Nic);\r
+    Private->Ip6Nic = NULL;\r
   }\r
 }\r
 \r
@@ -142,37 +228,37 @@ HttpBootIp4DxeDriverBindingSupported (
   // Try to open the DHCP4, HTTP4 and Device Path protocol.\r
   //\r
   Status = gBS->OpenProtocol (\r
-                   ControllerHandle,\r
-                   &gEfiDhcp4ServiceBindingProtocolGuid,\r
-                   NULL,\r
-                   This->DriverBindingHandle,\r
-                   ControllerHandle,\r
-                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                   );\r
+                  ControllerHandle,\r
+                  &gEfiDhcp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   Status = gBS->OpenProtocol (\r
-                   ControllerHandle,\r
-                   &gEfiHttpServiceBindingProtocolGuid,\r
-                   NULL,\r
-                   This->DriverBindingHandle,\r
-                   ControllerHandle,\r
-                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                   );\r
+                  ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   Status = gBS->OpenProtocol (\r
-                   ControllerHandle,\r
-                   &gEfiDevicePathProtocolGuid,\r
-                   NULL,\r
-                   This->DriverBindingHandle,\r
-                   ControllerHandle,\r
-                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                   );\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
 \r
   return Status;\r
 }\r
@@ -235,25 +321,83 @@ HttpBootIp4DxeDriverBindingStart (
                   ControllerHandle,\r
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                   );\r
+\r
   if (!EFI_ERROR (Status)) {\r
-    return EFI_ALREADY_STARTED;\r
-  }\r
+      Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
+  } else {\r
+    //\r
+    // Initialize the private data structure.\r
+    //\r
+    Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));\r
+    if (Private == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
+    Private->Controller = ControllerHandle;\r
+    Private->Image = This->ImageHandle;\r
+    InitializeListHead (&Private->CacheList);\r
+    //\r
+    // Get the NII interface if it exists, it's not required.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+                    (VOID **) &Private->Nii,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Private->Nii = NULL;\r
+    }\r
 \r
-  //\r
-  // Initialize the private data structure.\r
-  //\r
-  Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));\r
-  if (Private == NULL) {\r
+    //\r
+    // Open Device Path Protocol to prepare for appending IP and URI node.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    (VOID **) &Private->ParentDevicePath,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    //\r
+    // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
+    // NIC handle and the private data.\r
+    //\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &ControllerHandle,\r
+                    &gEfiCallerIdGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &Private->Id\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+      \r
+  }\r
+  \r
+  if (Private->Ip4Nic != NULL) {\r
+    //\r
+    // Already created before\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));\r
+  if (Private->Ip4Nic == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
-  Private->Controller = ControllerHandle;\r
-  Private->Image = This->ImageHandle;\r
-  Private->UsingIpv6 = FALSE;\r
-  InitializeListHead (&Private->CacheList);\r
-\r
+  Private->Ip4Nic->Private   = Private;\r
+  Private->Ip4Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
+  \r
   //\r
-  // Create DHCP child instance.\r
+  // Create DHCP4 child instance.\r
   //\r
   Status = NetLibCreateServiceChild (\r
              ControllerHandle,\r
@@ -264,7 +408,7 @@ HttpBootIp4DxeDriverBindingStart (
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-\r
+  \r
   Status = gBS->OpenProtocol (\r
                   Private->Dhcp4Child,\r
                   &gEfiDhcp4ProtocolGuid,\r
@@ -276,7 +420,7 @@ HttpBootIp4DxeDriverBindingStart (
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-\r
+  \r
   //\r
   // Get the Ip4Config2 protocol, it's required to configure the default gateway address.\r
   //\r
@@ -291,37 +435,7 @@ HttpBootIp4DxeDriverBindingStart (
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-\r
-  //\r
-  // Get the NII interface if it exists, it's not required.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  ControllerHandle,\r
-                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
-                  (VOID **) &Private->Nii,\r
-                  This->DriverBindingHandle,\r
-                  ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    Private->Nii = NULL;\r
-  }\r
-\r
-  //\r
-  // Open Device Path Protocol to prepare for appending IP and URI node.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  ControllerHandle,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &Private->ParentDevicePath,\r
-                  This->DriverBindingHandle,\r
-                  ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
-\r
+  \r
   //\r
   // Append IPv4 device path node.\r
   //\r
@@ -340,7 +454,7 @@ HttpBootIp4DxeDriverBindingStart (
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_ERROR;\r
   }\r
-\r
+  \r
   //\r
   // Append URI device path node.\r
   //\r
@@ -352,62 +466,49 @@ HttpBootIp4DxeDriverBindingStart (
   Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
   Node->DevPath.SubType = MSG_URI_DP;\r
   SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
-  Private->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+  Private->Ip4Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
   FreePool (Node);\r
   FreePool (DevicePath);\r
-  if (Private->DevicePath == NULL) {\r
+  if (Private->Ip4Nic->DevicePath == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_ERROR;\r
   }\r
-\r
+  \r
   //\r
   // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.\r
   //\r
-  CopyMem (&Private->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));\r
+  CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL));\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &Private->ChildHandle,\r
+                  &Private->Ip4Nic->Controller,\r
                   &gEfiLoadFileProtocolGuid,\r
-                  &Private->LoadFile,\r
+                  &Private->Ip4Nic->LoadFile,\r
                   &gEfiDevicePathProtocolGuid,\r
-                  Private->DevicePath,\r
+                  Private->Ip4Nic->DevicePath,\r
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-\r
-  //\r
-  // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
-  // NIC handle and the private data.\r
-  //\r
-  Status = gBS->InstallProtocolInterface (\r
-                  &ControllerHandle,\r
-                  &gEfiCallerIdGuid,\r
-                  EFI_NATIVE_INTERFACE,\r
-                  &Private->Id\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
-\r
+  \r
   //\r
   // Open the Caller Id child to setup a parent-child relationship between\r
-  // real NIC handle and the HTTP boot child handle.\r
+  // real NIC handle and the HTTP boot Ipv4 NIC handle.\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
                   &gEfiCallerIdGuid,\r
                   (VOID **) &Id,\r
                   This->DriverBindingHandle,\r
-                  Private->ChildHandle,\r
+                  Private->Ip4Nic->Controller,\r
                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-\r
+  \r
   return EFI_SUCCESS;\r
 \r
+    \r
 ON_ERROR:\r
   \r
   HttpBootDestroyIp4Children (This, Private);\r
@@ -416,6 +517,7 @@ ON_ERROR:
   return Status;\r
 }\r
 \r
+\r
 /**\r
   Stops a device controller or a bus controller.\r
   \r
@@ -509,51 +611,560 @@ HttpBootIp4DxeDriverBindingStop (
   // Destory all child instance and uninstall protocol interface.\r
   //\r
   HttpBootDestroyIp4Children (This, Private);\r
+  \r
+  if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {\r
+    //\r
+    // Release the cached data.\r
+    //\r
+    HttpBootFreeCacheList (Private);\r
+    \r
+    gBS->UninstallProtocolInterface (\r
+           NicHandle,\r
+           &gEfiCallerIdGuid,\r
+           &Private->Id\r
+           );\r
+    FreePool (Private);\r
 \r
-  //\r
-  // Release the cached data.\r
-  //\r
-  HttpBootFreeCacheList (Private);\r
-\r
-  gBS->UninstallProtocolInterface (\r
-         NicHandle,\r
-         &gEfiCallerIdGuid,\r
-         &Private->Id\r
-         );\r
-  FreePool (Private);\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  This is the declaration of an EFI image entry point. This entry point is\r
-  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
-  both device drivers and bus drivers.\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
 \r
-  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.\r
-  @param[in]  SystemTable       A pointer to the EFI System Table.\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
 \r
-  @retval EFI_SUCCESS           The operation completed successfully.\r
-  @retval Others                An unexpected error occurred.\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
 \r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpBootDxeDriverEntryPoint (\r
-  IN EFI_HANDLE        ImageHandle,\r
-  IN EFI_SYSTEM_TABLE  *SystemTable\r
+HttpBootIp6DxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
+  EFI_STATUS                    Status;\r
+  \r
   //\r
-  // Install UEFI Driver Model protocol(s).\r
+  // Try to open the DHCP6, HTTP and Device Path protocol.\r
   //\r
-  return EfiLibInstallDriverBindingComponentName2 (\r
-           ImageHandle,\r
-           SystemTable,\r
-           &gHttpBootIp4DxeDriverBinding,\r
-           ImageHandle,\r
-           &gHttpBootDxeComponentName,\r
-           &gHttpBootDxeComponentName2\r
-           );\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDhcp6ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootIp6DxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  HTTP_BOOT_PRIVATE_DATA     *Private;\r
+  EFI_DEV_PATH               *Node;\r
+  EFI_DEVICE_PATH_PROTOCOL   *DevicePath;\r
+  UINT32                     *Id;\r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiCallerIdGuid,\r
+                  (VOID **) &Id,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  \r
+  if (!EFI_ERROR (Status)) {\r
+      Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
+  } else {\r
+    //\r
+    // Initialize the private data structure.\r
+    //\r
+    Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));\r
+    if (Private == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
+    Private->Controller = ControllerHandle;\r
+    Private->Image = This->ImageHandle;\r
+    InitializeListHead (&Private->CacheList);\r
+    //\r
+    // Get the NII interface if it exists, it's not required.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+                    (VOID **) &Private->Nii,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Private->Nii = NULL;\r
+    }\r
+\r
+    //\r
+    // Open Device Path Protocol to prepare for appending IP and URI node.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    (VOID **) &Private->ParentDevicePath,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    //\r
+    // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
+    // NIC handle and the private data.\r
+    //\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &ControllerHandle,\r
+                    &gEfiCallerIdGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &Private->Id\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+      \r
+  }\r
+  \r
+  if (Private->Ip6Nic != NULL) {\r
+    //\r
+    // Already created before\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));\r
+  if (Private->Ip6Nic == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  Private->Ip6Nic->Private   = Private;\r
+  Private->Ip6Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
+\r
+  //\r
+  // Create Dhcp6 child and open Dhcp6 protocol\r
+  Status = NetLibCreateServiceChild (\r
+             ControllerHandle,\r
+             This->DriverBindingHandle,\r
+             &gEfiDhcp6ServiceBindingProtocolGuid,\r
+             &Private->Dhcp6Child\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Private->Dhcp6Child,\r
+                  &gEfiDhcp6ProtocolGuid,\r
+                  (VOID **) &Private->Dhcp6,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Create Ip6 child and open Ip6 protocol for background ICMP packets.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+              ControllerHandle,\r
+              This->DriverBindingHandle,\r
+              &gEfiIp6ServiceBindingProtocolGuid,\r
+              &Private->Ip6Child\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Private->Ip6Child,\r
+                  &gEfiIp6ProtocolGuid,\r
+                  (VOID **) &Private->Ip6,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Locate Ip6Config protocol, it's required to configure the default gateway address.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiIp6ConfigProtocolGuid,\r
+                  (VOID **) &Private->Ip6Config,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Append IPv6 device path node.\r
+  //\r
+  Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));\r
+  if (Node == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+  Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;\r
+  Node->Ipv6.Header.SubType = MSG_IPv6_DP;\r
+  Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;\r
+  SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));\r
+  DevicePath = AppendDevicePathNode(Private->ParentDevicePath, (EFI_DEVICE_PATH*) Node);\r
+  FreePool(Node);\r
+  if (DevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Append URI device path node.\r
+  //\r
+  Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
+  if (Node == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+  Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
+  Node->DevPath.SubType = MSG_URI_DP;\r
+  SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
+  Private->Ip6Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+  FreePool (Node);\r
+  FreePool (DevicePath);\r
+  if (Private->Ip6Nic->DevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.\r
+  //\r
+  CopyMem (&Private->Ip6Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Private->Ip6Nic->Controller,\r
+                  &gEfiLoadFileProtocolGuid,\r
+                  &Private->Ip6Nic->LoadFile,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  Private->Ip6Nic->DevicePath,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Open the Caller Id child to setup a parent-child relationship between\r
+  // real NIC handle and the HTTP boot child handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiCallerIdGuid,\r
+                  (VOID **) &Id,\r
+                  This->DriverBindingHandle,\r
+                  Private->Ip6Nic->Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+   \r
+ON_ERROR:\r
+  \r
+ HttpBootDestroyIp6Children(This, Private);\r
+ FreePool (Private);\r
+\r
+ return Status;\r
\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootIp6DxeDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
+  HTTP_BOOT_PRIVATE_DATA          *Private;\r
+  EFI_HANDLE                      NicHandle;\r
+  UINT32                          *Id;\r
+\r
+  //\r
+  // Try to get the Load File Protocol from the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiLoadFileProtocolGuid,\r
+                  (VOID **) &LoadFile,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // If failed, try to find the NIC handle for this controller.\r
+    //\r
+    NicHandle = HttpBootGetNicByIp6Children (ControllerHandle);\r
+    if (NicHandle == NULL) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Try to retrieve the private data by the Caller Id Guid.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    NicHandle,\r
+                    &gEfiCallerIdGuid,\r
+                    (VOID **) &Id,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);\r
+  } else {\r
+    Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);\r
+    NicHandle = Private->Controller;\r
+  }\r
+\r
+  //\r
+  // Disable the HTTP boot function.\r
+  //\r
+  Status = HttpBootStop (Private);\r
+  if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Destory all child instance and uninstall protocol interface.\r
+  //\r
+  HttpBootDestroyIp6Children (This, Private);\r
+\r
+  if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {\r
+    //\r
+    // Release the cached data.\r
+    //\r
+    HttpBootFreeCacheList (Private);\r
+        \r
+    gBS->UninstallProtocolInterface (\r
+           NicHandle,\r
+           &gEfiCallerIdGuid,\r
+           &Private->Id\r
+           );\r
+    FreePool (Private);\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  This is the declaration of an EFI image entry point. This entry point is\r
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
+  both device drivers and bus drivers.\r
+\r
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.\r
+  @param[in]  SystemTable       A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+  @retval Others                An unexpected error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootDxeDriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS   Status;\r
+  //\r
+  // Install UEFI Driver Model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gHttpBootIp4DxeDriverBinding,\r
+             ImageHandle,\r
+             &gHttpBootDxeComponentName,\r
+             &gHttpBootDxeComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gHttpBootIp6DxeDriverBinding,\r
+             NULL,\r
+             &gHttpBootDxeComponentName,\r
+             &gHttpBootDxeComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces(\r
+           ImageHandle,\r
+           &gEfiDriverBindingProtocolGuid,\r
+           &gHttpBootIp4DxeDriverBinding,\r
+           &gEfiComponentName2ProtocolGuid,\r
+           &gHttpBootDxeComponentName2,\r
+           &gEfiComponentNameProtocolGuid,\r
+           &gHttpBootDxeComponentName,\r
+           NULL\r
+           );\r
+  }\r
+  return Status;\r
 }\r
 \r
index 08415f6e0c3cd596b0132ee10f60858067b8c50d..452c8f4906db386ea896301a869d2cef01b9a93e 100644 (file)
@@ -41,9 +41,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 #include <Protocol/NetworkInterfaceIdentifier.h>\r
 #include <Protocol/Dhcp4.h>\r
+#include <Protocol/Dhcp6.h>\r
+#include <Protocol/Dns6.h>\r
 #include <Protocol/Http.h>\r
 #include <Protocol/Ip4Config2.h>\r
-\r
+#include <Protocol/Ip6Config.h>\r
 //\r
 // Produced Protocols\r
 //\r
@@ -65,29 +67,45 @@ extern EFI_COMPONENT_NAME_PROTOCOL  gHttpBootDxeComponentName;
 // Private data structure\r
 //\r
 typedef struct _HTTP_BOOT_PRIVATE_DATA      HTTP_BOOT_PRIVATE_DATA;\r
+typedef struct _HTTP_BOOT_VIRTUAL_NIC       HTTP_BOOT_VIRTUAL_NIC;\r
 \r
 //\r
 // Include files with internal function prototypes\r
 //\r
 #include "HttpBootComponentName.h"\r
 #include "HttpBootDhcp4.h"\r
+#include "HttpBootDhcp6.h"\r
 #include "HttpBootImpl.h"\r
 #include "HttpBootSupport.h"\r
 #include "HttpBootClient.h"\r
 \r
 typedef union {\r
   HTTP_BOOT_DHCP4_PACKET_CACHE              Dhcp4;\r
+  HTTP_BOOT_DHCP6_PACKET_CACHE              Dhcp6;\r
 } HTTP_BOOT_DHCP_PACKET_CACHE;\r
 \r
+struct _HTTP_BOOT_VIRTUAL_NIC {\r
+  UINT32                                    Signature;\r
+  EFI_HANDLE                                Controller;\r
+  EFI_LOAD_FILE_PROTOCOL                    LoadFile;\r
+  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;\r
+  HTTP_BOOT_PRIVATE_DATA                    *Private;\r
+};\r
+\r
 struct _HTTP_BOOT_PRIVATE_DATA {\r
   UINT32                                    Signature;\r
   EFI_HANDLE                                Controller;\r
   EFI_HANDLE                                Image;\r
 \r
+  HTTP_BOOT_VIRTUAL_NIC                     *Ip4Nic;\r
+  HTTP_BOOT_VIRTUAL_NIC                     *Ip6Nic;\r
+\r
   //\r
   // Cousumed children\r
   //\r
+  EFI_HANDLE                                Ip6Child;\r
   EFI_HANDLE                                Dhcp4Child;\r
+  EFI_HANDLE                                Dhcp6Child;\r
   HTTP_IO                                   HttpIo;\r
   BOOLEAN                                   HttpCreated;\r
 \r
@@ -95,14 +113,13 @@ struct _HTTP_BOOT_PRIVATE_DATA {
   // Consumed protocol\r
   //\r
   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
+  EFI_IP6_PROTOCOL                          *Ip6;\r
   EFI_IP4_CONFIG2_PROTOCOL                  *Ip4Config2;\r
+  EFI_IP6_CONFIG_PROTOCOL                   *Ip6Config;\r
   EFI_DHCP4_PROTOCOL                        *Dhcp4;\r
+  EFI_DHCP6_PROTOCOL                        *Dhcp6;\r
   EFI_DEVICE_PATH_PROTOCOL                  *ParentDevicePath;\r
 \r
-  //\r
-  // Produced children\r
-  //\r
-  EFI_HANDLE                                ChildHandle;\r
   \r
   //\r
   // Produced protocol\r
@@ -119,10 +136,12 @@ struct _HTTP_BOOT_PRIVATE_DATA {
   EFI_IP_ADDRESS                            StationIp;\r
   EFI_IP_ADDRESS                            SubnetMask;\r
   EFI_IP_ADDRESS                            GatewayIp;\r
+  EFI_IP_ADDRESS                            ServerIp;\r
   UINT16                                    Port;\r
   CHAR8                                     *BootFileUri;\r
   VOID                                      *BootFileUriParser;\r
   UINTN                                     BootFileSize;\r
+  BOOLEAN                                   NoGateway;\r
 \r
   //\r
   // Cached HTTP data\r
@@ -167,9 +186,10 @@ struct _HTTP_BOOT_PRIVATE_DATA {
 };\r
 \r
 #define HTTP_BOOT_PRIVATE_DATA_SIGNATURE          SIGNATURE_32 ('H', 'B', 'P', 'D')\r
+#define HTTP_BOOT_VIRTUAL_NIC_SIGNATURE           SIGNATURE_32 ('H', 'B', 'V', 'N')\r
 #define HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE(a)   CR (a, HTTP_BOOT_PRIVATE_DATA, LoadFile, HTTP_BOOT_PRIVATE_DATA_SIGNATURE)\r
 #define HTTP_BOOT_PRIVATE_DATA_FROM_ID(a)         CR (a, HTTP_BOOT_PRIVATE_DATA, Id, HTTP_BOOT_PRIVATE_DATA_SIGNATURE)\r
-\r
+#define HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE(a)    CR (a, HTTP_BOOT_VIRTUAL_NIC, LoadFile, HTTP_BOOT_VIRTUAL_NIC_SIGNATURE)\r
 extern EFI_LOAD_FILE_PROTOCOL               gHttpBootDxeLoadFile;\r
 \r
 /**\r
@@ -300,4 +320,131 @@ HttpBootIp4DxeDriverBindingStop (
   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
   );\r
 \r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootIp6DxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootIp6DxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootIp6DxeDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
+  );\r
 #endif\r
index 18f8f796f0cb6ca9e05477908a7cf877dd54f1df..e24b568ddc88756327ea64dfaebcd478c6bfc178 100644 (file)
@@ -35,6 +35,8 @@
   HttpBootImpl.c\r
   HttpBootDhcp4.h\r
   HttpBootDhcp4.c\r
+  HttpBootDhcp6.h\r
+  HttpBootDhcp6.c\r
   HttpBootSupport.h\r
   HttpBootSupport.c\r
   HttpBootClient.h\r
   gEfiDhcp4ServiceBindingProtocolGuid             ## TO_START\r
   gEfiDhcp4ProtocolGuid                           ## TO_START\r
   gEfiIp4Config2ProtocolGuid                      ## TO_START\r
+  gEfiDhcp6ServiceBindingProtocolGuid             ## TO_START\r
+  gEfiDhcp6ProtocolGuid                           ## TO_START\r
+  gEfiDns6ServiceBindingProtocolGuid              ## SOMETIMES_CONSUMES\r
+  gEfiDns6ProtocolGuid                            ## SOMETIMES_CONSUMES\r
+  gEfiIp6ServiceBindingProtocolGuid               ## TO_START\r
+  gEfiIp6ProtocolGuid                             ## TO_START\r
+  gEfiIp6ConfigProtocolGuid                       ## TO_START\r
   gEfiNetworkInterfaceIdentifierProtocolGuid_31   ## SOMETIMES_CONSUMES\r
 \r
 [UserExtensions.TianoCore."ExtraFiles"]\r
index 68a33794b27664cc8e6c615017d8eb3b8ce6fe20..fe743df852821e3069aa7411f3ca1f91d394da02 100644 (file)
Binary files a/NetworkPkg/HttpBootDxe/HttpBootDxe.uni and b/NetworkPkg/HttpBootDxe/HttpBootDxe.uni differ
index eee63c21d3a907e2415ab7ddfbeb6f4875c9ed1a..9ea0d7f95f93eb26aa7bbd58e59196fe739b696f 100644 (file)
@@ -18,6 +18,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
   Enable the use of UEFI HTTP boot function.\r
 \r
   @param[in]    Private            The pointer to the driver's private data.\r
+  @param[in]    UsingIpv6          Specifies the type of IP addresses that are to be\r
+                                   used during the session that is being started.\r
+                                   Set to TRUE for IPv6, and FALSE for IPv4.\r
 \r
   @retval EFI_SUCCESS              HTTP boot was successfully enabled.\r
   @retval EFI_INVALID_PARAMETER    Private is NULL.\r
@@ -26,10 +29,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/\r
 EFI_STATUS\r
 HttpBootStart (\r
-  IN HTTP_BOOT_PRIVATE_DATA           *Private\r
+  IN HTTP_BOOT_PRIVATE_DATA           *Private,\r
+  IN BOOLEAN                          UsingIpv6\r
   )\r
 {\r
-  UINTN          Index;\r
+  UINTN                Index;\r
+  EFI_STATUS           Status;\r
 \r
   if (Private == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -39,25 +44,47 @@ HttpBootStart (
     return EFI_ALREADY_STARTED;\r
   }\r
 \r
+  //\r
+  // Detect whether using ipv6 or not, and set it to the private data.\r
+  //\r
+  if (UsingIpv6 && Private->Ip6Nic != NULL) {\r
+    Private->UsingIpv6 = TRUE;\r
+  } else if (!UsingIpv6 && Private->Ip4Nic != NULL) {\r
+    Private->UsingIpv6 = FALSE;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  //\r
+  // Init the content of cached DHCP offer list.\r
+  //\r
+  ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
   if (!Private->UsingIpv6) {\r
-    //\r
-    // Init the content of cached DHCP offer list.\r
-    //\r
-    ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
     for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
       Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_BOOT_DHCP4_PACKET_MAX_SIZE;\r
     }\r
   } else {\r
-    ASSERT (FALSE);\r
+    for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
+      Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = HTTP_BOOT_DHCP6_PACKET_MAX_SIZE;\r
+    }\r
   }\r
 \r
+  if (Private->UsingIpv6) {\r
+    //\r
+    // Set Ip6 policy to Automatic to start the Ip6 router discovery.\r
+    //\r
+    Status = HttpBootSetIp6Policy (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
   Private->Started = TRUE;\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information.\r
+  Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.\r
 \r
   @param[in]    Private            The pointer to the driver's private data.\r
 \r
@@ -86,9 +113,15 @@ HttpBootDhcp (
   Status = EFI_DEVICE_ERROR;\r
 \r
   if (!Private->UsingIpv6) {\r
+    //\r
+    // Start D.O.R.A process to get a IPv4 address and other boot information.\r
+    //\r
     Status = HttpBootDhcp4Dora (Private);\r
   } else {\r
-    ASSERT (FALSE);\r
+     //\r
+    // Start S.A.R.R process to get a IPv6 address and other boot information.\r
+    //\r
+    Status = HttpBootDhcp6Sarr (Private);\r
   }\r
 \r
   return Status;\r
@@ -241,7 +274,7 @@ HttpBootStop (
   Private->BootFileUriParser = NULL;\r
   Private->BootFileSize = 0;\r
   Private->SelectIndex = 0;\r
-  Private->SelectProxyType = HttpOfferTypeMax;\r
+  Private->SelectProxyType = HttpOfferTypeMax; \r
 \r
   if (!Private->UsingIpv6) {\r
     //\r
@@ -256,7 +289,17 @@ HttpBootStop (
       }\r
     }\r
   } else {\r
-    ASSERT (FALSE);\r
+    //\r
+    // Stop and release the DHCP6 child.\r
+    //\r
+    Private->Dhcp6->Stop (Private->Dhcp6);\r
+    Private->Dhcp6->Configure (Private->Dhcp6, NULL);\r
+    \r
+    for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
+      if (Private->OfferBuffer[Index].Dhcp6.UriParser) {\r
+        HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp6.UriParser);\r
+      }\r
+    }\r
   }\r
   \r
   ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
@@ -309,7 +352,9 @@ HttpBootDxeLoadFile (
   )\r
 {\r
   HTTP_BOOT_PRIVATE_DATA        *Private;\r
+  HTTP_BOOT_VIRTUAL_NIC         *VirtualNic;\r
   BOOLEAN                       MediaPresent;\r
+  BOOLEAN                       UsingIpv6;\r
   EFI_STATUS                    Status;\r
 \r
   if (This == NULL || BufferSize == NULL) {\r
@@ -323,8 +368,10 @@ HttpBootDxeLoadFile (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (This);\r
-\r
+  VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This);\r
+  Private = VirtualNic->Private;\r
+  UsingIpv6 = FALSE;\r
+  \r
   //\r
   // Check media status before HTTP boot start\r
   //\r
@@ -334,10 +381,26 @@ HttpBootDxeLoadFile (
     return EFI_NO_MEDIA;\r
   }\r
 \r
+  //\r
+  // Check whether the virtual nic is using IPv6 or not.\r
+  //\r
+  if (VirtualNic == Private->Ip6Nic) {\r
+    UsingIpv6 = TRUE;\r
+  }\r
+  \r
   //\r
   // Initialize HTTP boot and load the boot file.\r
   //\r
-  Status = HttpBootStart (Private);\r
+  Status = HttpBootStart (Private, UsingIpv6);\r
+  if (Status == EFI_ALREADY_STARTED && UsingIpv6 != Private->UsingIpv6) {\r
+    //\r
+    // Http boot Driver has already been started but not on the required IP version, restart it.\r
+    //\r
+    Status = HttpBootStop (Private);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = HttpBootStart (Private, UsingIpv6);\r
+    }\r
+  }\r
   if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {\r
     Status = HttpBootLoadFile (Private, BufferSize, Buffer);\r
   }\r
@@ -345,11 +408,19 @@ HttpBootDxeLoadFile (
   if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {\r
     HttpBootStop (Private);\r
   } else {\r
-    //\r
-    // Stop and release the DHCP4 child.\r
-    //\r
-    Private->Dhcp4->Stop (Private->Dhcp4);\r
-    Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
+    if (!Private->UsingIpv6) {\r
+      //\r
+      // Stop and release the DHCP4 child.\r
+      //\r
+      Private->Dhcp4->Stop (Private->Dhcp4);\r
+      Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
+    } else {\r
+      //\r
+      // Stop and release the DHCP6 child.\r
+      //\r
+      Private->Dhcp6->Stop (Private->Dhcp6);\r
+      Private->Dhcp6->Configure (Private->Dhcp6, NULL);\r
+    }\r
   }\r
 \r
   return Status;\r
index a2e9f5a3281c3549dad228039cda80bae2990a74..70663381752c3c2ade559d99c60a7e9064dc3cda 100644 (file)
@@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define __EFI_HTTP_BOOT_IMPL_H__\r
 \r
 /**\r
-  Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information.\r
+  Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.\r
 \r
   @param[in]    Private            The pointer to the driver's private data.\r
 \r
index 761643141f916142a32bf6d3630916d2be4e3a97..d08111f66107e84efceab75e9554ed45821c7259 100644 (file)
@@ -42,6 +42,31 @@ HttpBootGetNicByIp4Children (
   return NicHandle;\r
 }\r
 \r
+/**\r
+  Get the Nic handle using any child handle in the IPv6 stack.\r
+\r
+  @param[in]  ControllerHandle    Pointer to child handle over IPv6.\r
+\r
+  @return NicHandle               The pointer to the Nic handle.\r
+  @return NULL                    Can't find the Nic handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HttpBootGetNicByIp6Children (\r
+  IN EFI_HANDLE                 ControllerHandle\r
+  )\r
+{\r
+  EFI_HANDLE                    NicHandle;\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
+  if (NicHandle == NULL) {\r
+    NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
+    if (NicHandle == NULL) {\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  return NicHandle;\r
+}\r
 \r
 /**\r
   This function is to convert UINTN to ASCII string with the required formatting.\r
@@ -89,6 +114,242 @@ HttpBootShowIp4Addr (
   }\r
 }\r
 \r
+/**\r
+  This function is to display the IPv6 address.\r
+\r
+  @param[in]  Ip        The pointer to the IPv6 address.\r
+\r
+**/\r
+VOID\r
+HttpBootShowIp6Addr (\r
+  IN EFI_IPv6_ADDRESS   *Ip\r
+  )\r
+{\r
+  UINTN                 Index;\r
+\r
+  for (Index = 0; Index < 16; Index++) {\r
+\r
+    if (Ip->Addr[Index] != 0) {\r
+      AsciiPrint ("%x", Ip->Addr[Index]);\r
+    }\r
+    Index++;\r
+    if (Index > 15) {\r
+      return;\r
+    }\r
+    if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
+      AsciiPrint ("0");\r
+    }\r
+    AsciiPrint ("%x", Ip->Addr[Index]);\r
+    if (Index < 15) {\r
+      AsciiPrint (":");\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Notify the callback function when an event is triggered.\r
+\r
+  @param[in]  Event           The triggered event.\r
+  @param[in]  Context         The opaque parameter to the function.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpBootCommonNotify (\r
+  IN EFI_EVENT           Event,\r
+  IN VOID                *Context\r
+  )\r
+{\r
+  *((BOOLEAN *) Context) = TRUE;\r
+}\r
+\r
+/**\r
+  Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  Private             The pointer to the driver's private data.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.  \r
+**/\r
+EFI_STATUS\r
+HttpBootDns (\r
+  IN     HTTP_BOOT_PRIVATE_DATA   *Private,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv6_ADDRESS         *IpAddress \r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_DNS6_PROTOCOL               *Dns6;\r
+  EFI_DNS6_CONFIG_DATA            Dns6ConfigData;\r
+  EFI_DNS6_COMPLETION_TOKEN       Token;\r
+  EFI_HANDLE                      Dns6Handle;\r
+  EFI_IP6_CONFIG_PROTOCOL         *Ip6Config;\r
+  EFI_IPv6_ADDRESS                *DnsServerList;\r
+  UINTN                           DnsServerListCount;\r
+  UINTN                           DataSize;\r
+  BOOLEAN                         IsDone;  \r
+  \r
+  DnsServerList       = NULL;\r
+  DnsServerListCount  = 0;\r
+  Dns6                = NULL;\r
+  Dns6Handle          = NULL;\r
+  ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
+  \r
+  //\r
+  // Get DNS server list from EFI IPv6 Configuration protocol.\r
+  //\r
+  Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Get the required size.\r
+    //\r
+    DataSize = 0;\r
+    Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      DnsServerList = AllocatePool (DataSize);\r
+      if (DnsServerList == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }  \r
+\r
+      Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (DnsServerList);\r
+        DnsServerList = NULL;\r
+      } else {\r
+        DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Create a DNSv6 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Private->Controller,\r
+             Private->Image,\r
+             &gEfiDns6ServiceBindingProtocolGuid,\r
+             &Dns6Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  } \r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  Dns6Handle,\r
+                  &gEfiDns6ProtocolGuid,\r
+                  (VOID **) &Dns6,\r
+                  Private->Image,\r
+                  Private->Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Configure DNS6 instance for the DNS server address and protocol.\r
+  //\r
+  ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
+  Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
+  Dns6ConfigData.DnsServerList  = DnsServerList;\r
+  Dns6ConfigData.EnableDnsCache = TRUE;\r
+  Dns6ConfigData.Protocol       = EFI_IP_PROTO_UDP;\r
+  IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
+  Status = Dns6->Configure (\r
+                    Dns6,\r
+                    &Dns6ConfigData\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+  \r
+  Token.Status = EFI_NOT_READY;\r
+  IsDone       = FALSE;\r
+  //\r
+  // Create event to set the  IsDone flag when name resolution is finished.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpBootCommonNotify,\r
+                  &IsDone,\r
+                  &Token.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Start asynchronous name resolution.\r
+  //\r
+  Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  while (!IsDone) {\r
+    Dns6->Poll (Dns6);\r
+  }\r
+  \r
+  //\r
+  // Name resolution is done, check result.\r
+  //\r
+  Status = Token.Status;  \r
+  if (!EFI_ERROR (Status)) {\r
+    if (Token.RspData.H2AData == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // We just return the first IPv6 address from DNS protocol.\r
+    //\r
+    IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+Exit:\r
+\r
+  if (Token.Event != NULL) {\r
+    gBS->CloseEvent (Token.Event);\r
+  }\r
+  if (Token.RspData.H2AData != NULL) {\r
+    if (Token.RspData.H2AData->IpList != NULL) {\r
+      FreePool (Token.RspData.H2AData->IpList);\r
+    }\r
+    FreePool (Token.RspData.H2AData);\r
+  }\r
+\r
+  if (Dns6 != NULL) {\r
+    Dns6->Configure (Dns6, NULL);\r
+    \r
+    gBS->CloseProtocol (\r
+           Dns6Handle,\r
+           &gEfiDns6ProtocolGuid,\r
+           Private->Image,\r
+           Private->Controller\r
+           );\r
+  }\r
+\r
+  if (Dns6Handle != NULL) {\r
+    NetLibDestroyServiceChild (\r
+      Private->Controller,\r
+      Private->Image,\r
+      &gEfiDns6ServiceBindingProtocolGuid,\r
+      Dns6Handle\r
+      );\r
+  }\r
+\r
+  if (DnsServerList != NULL) {\r
+    FreePool (DnsServerList);\r
+  }\r
+  \r
+  return Status;  \r
+}\r
 /**\r
   Create a HTTP_IO_HEADER to hold the HTTP header items.\r
 \r
@@ -100,7 +361,7 @@ HttpBootShowIp4Addr (
 HTTP_IO_HEADER *\r
 HttpBootCreateHeader (\r
   UINTN                     MaxHeaderCount\r
-)\r
+  )\r
 {\r
   HTTP_IO_HEADER        *HttpIoHeader;\r
 \r
@@ -254,23 +515,6 @@ HttpBootSetHeader (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Notify the callback function when an event is triggered.\r
-\r
-  @param[in]  Event           The triggered event.\r
-  @param[in]  Context         The opaque parameter to the function.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-HttpIoCommonNotify (\r
-  IN EFI_EVENT           Event,\r
-  IN VOID                *Context\r
-  )\r
-{\r
-  *((BOOLEAN *) Context) = TRUE;\r
-}\r
-\r
 /**\r
   Create a HTTP_IO to access the HTTP service. It will create and configure\r
   a HTTP child handle.\r
@@ -301,6 +545,7 @@ HttpIoCreateIo (
   EFI_STATUS                Status;\r
   EFI_HTTP_CONFIG_DATA      HttpConfigData;\r
   EFI_HTTPv4_ACCESS_POINT   Http4AccessPoint;\r
+  EFI_HTTPv6_ACCESS_POINT   Http6AccessPoint;\r
   EFI_HTTP_PROTOCOL         *Http;\r
   EFI_EVENT                 Event;\r
   \r
@@ -359,7 +604,10 @@ HttpIoCreateIo (
     IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
     HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint;   \r
   } else {\r
-    ASSERT (FALSE);\r
+    HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
+    Http6AccessPoint.LocalPort        = ConfigData->Config6.LocalPort;\r
+    IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
+    HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
   }\r
   \r
   Status = Http->Configure (Http, &HttpConfigData);\r
@@ -373,7 +621,7 @@ HttpIoCreateIo (
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
                   TPL_NOTIFY,\r
-                  HttpIoCommonNotify,\r
+                  HttpBootCommonNotify,\r
                   &HttpIo->IsTxDone,\r
                   &Event\r
                   );\r
@@ -386,7 +634,7 @@ HttpIoCreateIo (
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
                   TPL_NOTIFY,\r
-                  HttpIoCommonNotify,\r
+                  HttpBootCommonNotify,\r
                   &HttpIo->IsRxDone,\r
                   &Event\r
                   );\r
@@ -579,7 +827,7 @@ HttpIoRecvResponse (
   //\r
   // Store the received data into the wrapper.\r
   //\r
-  Status = HttpIo->ReqToken.Status;\r
+  Status = HttpIo->RspToken.Status;\r
   if (!EFI_ERROR (Status)) {\r
     ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
     ResponseData->Headers     = HttpIo->RspToken.Message->Headers;\r
index bef80e81d874930f51956037a6ed22a4bae48611..d5956720a7cf9465a8c78deb82c636f5198f76eb 100644 (file)
@@ -29,6 +29,20 @@ HttpBootGetNicByIp4Children (
   IN EFI_HANDLE                 ControllerHandle\r
   );\r
 \r
+/**\r
+  Get the Nic handle using any child handle in the IPv6 stack.\r
+\r
+  @param[in]  ControllerHandle    Pointer to child handle over IPv6.\r
+\r
+  @return NicHandle               The pointer to the Nic handle.\r
+  @return NULL                    Can't find the Nic handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HttpBootGetNicByIp6Children (\r
+  IN EFI_HANDLE                 ControllerHandle\r
+  );\r
+\r
 /**\r
   This function is to convert UINTN to ASCII string with the required formatting.\r
 \r
@@ -56,6 +70,17 @@ HttpBootShowIp4Addr (
   IN EFI_IPv4_ADDRESS   *Ip\r
   );\r
 \r
+/**\r
+  This function is to display the IPv6 address.\r
+\r
+  @param[in]  Ip        The pointer to the IPv6 address.\r
+\r
+**/\r
+VOID\r
+HttpBootShowIp6Addr (\r
+  IN EFI_IPv6_ADDRESS   *Ip\r
+  );\r
+\r
 //\r
 // A wrapper structure to hold the HTTP headers.\r
 //\r
@@ -122,11 +147,24 @@ typedef struct {
   UINT16                    LocalPort;\r
 } HTTP4_IO_CONFIG_DATA;\r
 \r
+//\r
+// HTTP_IO configuration data for IPv6\r
+//\r
+typedef struct {\r
+  EFI_HTTP_VERSION          HttpVersion;\r
+  UINT32                    RequestTimeOut;  // In milliseconds.\r
+  BOOLEAN                   UseDefaultAddress;\r
+  EFI_IPv6_ADDRESS          LocalIp;\r
+  UINT16                    LocalPort;\r
+} HTTP6_IO_CONFIG_DATA;\r
+\r
+\r
 //\r
 // HTTP_IO configuration\r
 //\r
 typedef union {\r
   HTTP4_IO_CONFIG_DATA       Config4;\r
+  HTTP6_IO_CONFIG_DATA       Config6;\r
 } HTTP_IO_CONFIG_DATA;\r
 \r
 //\r
@@ -160,6 +198,38 @@ typedef struct {
   CHAR8                       *Body;\r
 } HTTP_IO_RESOPNSE_DATA;\r
 \r
+/**\r
+  Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  Private             The pointer to the driver's private data.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.  \r
+**/\r
+EFI_STATUS\r
+HttpBootDns (\r
+  IN     HTTP_BOOT_PRIVATE_DATA   *Private,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv6_ADDRESS         *IpAddress \r
+  );\r
+\r
+/**\r
+  Notify the callback function when an event is triggered.\r
+\r
+  @param[in]  Event           The triggered event.\r
+  @param[in]  Context         The opaque parameter to the function.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpBootCommonNotify (\r
+  IN EFI_EVENT           Event,\r
+  IN VOID                *Context\r
+  );\r
+\r
 /**\r
   Create a HTTP_IO to access the HTTP service. It will create and configure\r
   a HTTP child handle.\r
index daebc173b5e9a971f115845228936d6d47657540..0f5fe180727025d475f7a535bf43b1639260caac 100644 (file)
@@ -194,11 +194,11 @@ Exit:
     Dns4->Configure (Dns4, NULL);\r
     \r
     gBS->CloseProtocol (\r
-          Dns4Handle,\r
-          &gEfiDns4ProtocolGuid,\r
-          Service->ImageHandle,\r
-          Service->ControllerHandle\r
-          );\r
+           Dns4Handle,\r
+           &gEfiDns4ProtocolGuid,\r
+           Service->ImageHandle,\r
+           Service->ControllerHandle\r
+           );\r
   }\r
 \r
   if (Dns4Handle != NULL) {\r
@@ -216,3 +216,200 @@ Exit:
   \r
   return Status;\r
 }\r
+\r
+/**\r
+  Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpDns6 (\r
+  IN     HTTP_PROTOCOL            *HttpInstance,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv6_ADDRESS         *IpAddress                \r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  HTTP_SERVICE                    *Service;\r
+  EFI_DNS6_PROTOCOL               *Dns6;\r
+  EFI_DNS6_CONFIG_DATA            Dns6ConfigData;\r
+  EFI_DNS6_COMPLETION_TOKEN       Token;\r
+  EFI_HANDLE                      Dns6Handle;\r
+  EFI_IP6_CONFIG_PROTOCOL         *Ip6Config;\r
+  EFI_IPv6_ADDRESS                *DnsServerList;\r
+  UINTN                           DnsServerListCount;\r
+  UINTN                           DataSize;\r
+  BOOLEAN                         IsDone;\r
+  \r
+\r
+  Service = HttpInstance->Service;\r
+  ASSERT (Service != NULL);\r
+\r
+  DnsServerList       = NULL;\r
+  DnsServerListCount  = 0;\r
+  Dns6                = NULL;\r
+  Dns6Handle          = NULL;\r
+  ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
+  \r
+  //\r
+  // Get DNS server list from EFI IPv6 Configuration protocol.\r
+  //\r
+  Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Get the required size.\r
+    //\r
+    DataSize = 0;\r
+    Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      DnsServerList = AllocatePool (DataSize);\r
+      if (DnsServerList == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }  \r
+\r
+      Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (DnsServerList);\r
+        DnsServerList = NULL;\r
+      } else {\r
+        DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create a DNSv6 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Service->ControllerHandle,\r
+             Service->ImageHandle,\r
+             &gEfiDns6ServiceBindingProtocolGuid,\r
+             &Dns6Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  } \r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  Dns6Handle,\r
+                  &gEfiDns6ProtocolGuid,\r
+                  (VOID **) &Dns6,\r
+                  Service->ImageHandle,\r
+                  Service->ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Configure DNS6 instance for the DNS server address and protocol.\r
+  //\r
+  ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
+  Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
+  Dns6ConfigData.DnsServerList  = DnsServerList;\r
+  Dns6ConfigData.EnableDnsCache = TRUE;\r
+  Dns6ConfigData.Protocol       = EFI_IP_PROTO_UDP;\r
+  IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &HttpInstance->Ipv6Node.LocalAddress);\r
+  Status = Dns6->Configure (\r
+                   Dns6,\r
+                   &Dns6ConfigData\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Token.Status = EFI_NOT_READY;\r
+  IsDone       = FALSE;\r
+  //\r
+  // Create event to set the  IsDone flag when name resolution is finished.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpCommonNotify,\r
+                  &IsDone,\r
+                  &Token.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Start asynchronous name resolution.\r
+  //\r
+  Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  while (!IsDone) {\r
+    Dns6->Poll (Dns6);\r
+  }\r
+\r
+  //\r
+  // Name resolution is done, check result.\r
+  //\r
+  Status = Token.Status;  \r
+  if (!EFI_ERROR (Status)) {\r
+    if (Token.RspData.H2AData == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // We just return the first IPv6 address from DNS protocol.\r
+    //\r
+    IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  \r
+Exit:\r
+\r
+  if (Token.Event != NULL) {\r
+    gBS->CloseEvent (Token.Event);\r
+  }\r
+  if (Token.RspData.H2AData != NULL) {\r
+    if (Token.RspData.H2AData->IpList != NULL) {\r
+      FreePool (Token.RspData.H2AData->IpList);\r
+    }\r
+    FreePool (Token.RspData.H2AData);\r
+  }\r
+\r
+  if (Dns6 != NULL) {\r
+    Dns6->Configure (Dns6, NULL);\r
+    \r
+    gBS->CloseProtocol (\r
+           Dns6Handle,\r
+           &gEfiDns6ProtocolGuid,\r
+           Service->ImageHandle,\r
+           Service->ControllerHandle\r
+           );\r
+  }\r
+\r
+  if (Dns6Handle != NULL) {\r
+    NetLibDestroyServiceChild (\r
+      Service->ControllerHandle,\r
+      Service->ImageHandle,\r
+      &gEfiDns6ServiceBindingProtocolGuid,\r
+      Dns6Handle\r
+      );\r
+  }\r
+\r
+  if (DnsServerList != NULL) {\r
+    FreePool (DnsServerList);\r
+  }\r
+  \r
+  return Status;  \r
+}\r
index 0fb418635ca5b6a0f280839e9def5d8653486987..fa0c8f4a99f3dd962f2fb6d5ec5131c7525578b1 100644 (file)
@@ -35,4 +35,24 @@ HttpDns4 (
      OUT EFI_IPv4_ADDRESS         *IpAddress                \r
   );\r
 \r
+/**\r
+  Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpDns6 (\r
+  IN     HTTP_PROTOCOL            *HttpInstance,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv6_ADDRESS         *IpAddress                \r
+  );\r
+\r
 #endif
\ No newline at end of file
index bd1d04e78cc430acbba194d78f2e5eb9e9b8a5a3..2518f4e707b608e1726999d3b84f04ca93add447 100644 (file)
@@ -20,15 +20,25 @@ EFI_HTTP_UTILITIES_PROTOCOL *mHttpUtilities = NULL;
 ///\r
 /// Driver Binding Protocol instance\r
 ///\r
-EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding = {\r
-  HttpDxeDriverBindingSupported,\r
-  HttpDxeDriverBindingStart,\r
-  HttpDxeDriverBindingStop,\r
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding = {\r
+  HttpDxeIp4DriverBindingSupported,\r
+  HttpDxeIp4DriverBindingStart,\r
+  HttpDxeIp4DriverBindingStop,\r
   HTTP_DRIVER_VERSION,\r
   NULL,\r
   NULL\r
 };\r
 \r
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding = {\r
+  HttpDxeIp6DriverBindingSupported,\r
+  HttpDxeIp6DriverBindingStart,\r
+  HttpDxeIp6DriverBindingStop,\r
+  HTTP_DRIVER_VERSION,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
 /**\r
   Create a HTTP driver service binding private instance.\r
 \r
@@ -73,33 +83,59 @@ HttpCreateService (
 /**\r
   Release all the resource used the HTTP service binding instance.\r
 \r
-  @param  HttpService        The HTTP private instance.\r
-\r
+  @param[in]  HttpService        The HTTP private instance.\r
+  @param[in]  UsingIpv6          Indicate use TCP4 protocol or TCP6 protocol.\r
+                                 if TRUE, use Tcp6 protocol.\r
+                                 if FALSE, use Tcp4 protocl.\r
 **/\r
 VOID\r
 HttpCleanService (\r
-  IN HTTP_SERVICE     *HttpService\r
+  IN HTTP_SERVICE     *HttpService,\r
+  IN BOOLEAN          UsingIpv6\r
   )\r
-{\r
+{ \r
+  \r
   if (HttpService == NULL) {\r
     return ;\r
   }\r
-\r
-  if (HttpService->TcpChildHandle != NULL) {\r
-    gBS->CloseProtocol (\r
-           HttpService->TcpChildHandle,\r
-           &gEfiTcp4ProtocolGuid,\r
-           HttpService->ImageHandle,\r
-           HttpService->ControllerHandle\r
-           );\r
-\r
-    NetLibDestroyServiceChild (\r
-      HttpService->ControllerHandle,\r
-      HttpService->ImageHandle,\r
-      &gEfiTcp4ServiceBindingProtocolGuid,\r
-      HttpService->TcpChildHandle\r
-      );\r
+  if (!UsingIpv6) {\r
+    if (HttpService->Tcp4ChildHandle != NULL) {\r
+      gBS->CloseProtocol (\r
+             HttpService->Tcp4ChildHandle,\r
+             &gEfiTcp4ProtocolGuid,\r
+             HttpService->ImageHandle,\r
+             HttpService->ControllerHandle\r
+             );\r
+    \r
+      NetLibDestroyServiceChild (\r
+        HttpService->ControllerHandle,\r
+        HttpService->ImageHandle,\r
+        &gEfiTcp4ServiceBindingProtocolGuid,\r
+        HttpService->Tcp4ChildHandle\r
+        );\r
+      \r
+      HttpService->Tcp4ChildHandle = NULL;\r
+    }\r
+  } else {\r
+    if (HttpService->Tcp6ChildHandle != NULL) {\r
+      gBS->CloseProtocol (\r
+             HttpService->Tcp6ChildHandle,\r
+             &gEfiTcp6ProtocolGuid,\r
+             HttpService->ImageHandle,\r
+             HttpService->ControllerHandle\r
+             );\r
+    \r
+      NetLibDestroyServiceChild (\r
+        HttpService->ControllerHandle,\r
+        HttpService->ImageHandle,\r
+        &gEfiTcp6ServiceBindingProtocolGuid,\r
+        HttpService->Tcp6ChildHandle\r
+        );\r
+      \r
+      HttpService->Tcp6ChildHandle = NULL;\r
+    }\r
   }\r
+  \r
 }\r
 \r
 /**\r
@@ -107,7 +143,7 @@ HttpCleanService (
   in the system.\r
 \r
   @param[in]     Event         Not used.\r
-  @param[in]     Context       The pointer to the IP4 config2 instance data.\r
+  @param[in]     Context       The pointer to the IP4 config2 instance data or IP6 Config instance data.\r
 \r
 **/\r
 VOID\r
@@ -122,7 +158,7 @@ HttpUtilitiesInstalledCallback (
          NULL, \r
          (VOID **) &mHttpUtilities\r
          );\r
-                \r
\r
   //\r
   // Close the event if Http utilities protocol is loacted.\r
   //\r
@@ -150,6 +186,7 @@ HttpDxeDriverEntryPoint (
   IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 { \r
+  EFI_STATUS     Status;\r
   VOID           *Registration;\r
 \r
   gBS->LocateProtocol (\r
@@ -174,14 +211,39 @@ HttpDxeDriverEntryPoint (
   //\r
   // Install UEFI Driver Model protocol(s).\r
   //\r
-  return EfiLibInstallDriverBindingComponentName2 (\r
-           ImageHandle,\r
-           SystemTable,\r
-           &gHttpDxeDriverBinding,\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gHttpDxeIp4DriverBinding,\r
+             ImageHandle,\r
+             &gHttpDxeComponentName,\r
+             &gHttpDxeComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gHttpDxeIp6DriverBinding,\r
+             NULL,\r
+             &gHttpDxeComponentName,\r
+             &gHttpDxeComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
            ImageHandle,\r
+           &gEfiDriverBindingProtocolGuid,\r
+           &gHttpDxeIp4DriverBinding,\r
+           &gEfiComponentName2ProtocolGuid,\r
+           &gHttpDxeComponentName2,\r
+           &gEfiComponentNameProtocolGuid,\r
            &gHttpDxeComponentName,\r
-           &gHttpDxeComponentName2\r
+           NULL\r
            );\r
+  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -223,6 +285,309 @@ HttpDestroyChildEntryInHandleBuffer (
   return ServiceBinding->DestroyChild (ServiceBinding, HttpInstance->Handle);\r
 }\r
 \r
+/**\r
+  Test to see if this driver supports ControllerHandle. This is the worker function for\r
+  HttpDxeIp4(6)DriverBindingSupported.\r
+\r
+  @param[in]  This                The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle    The handle of device to be tested.\r
+  @param[in]  RemainingDevicePath Optional parameter used to pick a specific child\r
+                                  device to be started.\r
+  @param[in]  IpVersion           IP_VERSION_4 or IP_VERSION_6.\r
+  \r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval EFI_UNSUPPORTED     This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL,\r
+  IN UINT8                        IpVersion\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_GUID                        *TcpServiceBindingProtocolGuid;\r
+\r
+  if (IpVersion == IP_VERSION_4) {\r
+    TcpServiceBindingProtocolGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+  } else {\r
+    TcpServiceBindingProtocolGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                ControllerHandle,\r
+                TcpServiceBindingProtocolGuid,\r
+                NULL,\r
+                This->DriverBindingHandle,\r
+                ControllerHandle,\r
+                EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Start this driver on ControllerHandle. This is the worker function for\r
+  HttpDxeIp4(6)DriverBindingStart.\r
+\r
+  @param[in]  This                 The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle     The handle of device to be started.\r
+  @param[in]  RemainingDevicePath  Optional parameter used to pick a specific child\r
+                                   device to be started.\r
+  @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.\r
+\r
+\r
+  @retval EFI_SUCCESS          This driver is installed to ControllerHandle.\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL,\r
+  IN UINT8                        IpVersion\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SERVICE_BINDING_PROTOCOL    *ServiceBinding;\r
+  HTTP_SERVICE                    *HttpService;\r
+  VOID                            *Interface;\r
+  BOOLEAN                         UsingIpv6;\r
+\r
+  UsingIpv6 = FALSE;\r
+\r
+  //\r
+  // Test for the Http service binding protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
+  } else {\r
+    Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    ASSERT (HttpService != NULL);\r
+      \r
+    //\r
+    // Install the HttpServiceBinding Protocol onto Controller\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &ControllerHandle,\r
+                    &gEfiHttpServiceBindingProtocolGuid,\r
+                    &HttpService->ServiceBinding,\r
+                    NULL\r
+                    );\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
+\r
+  if (IpVersion == IP_VERSION_4) {\r
+    \r
+    if (HttpService->Tcp4ChildHandle == NULL) {\r
+      //\r
+      // Create a TCP4 child instance, but do not configure it. This will establish the parent-child relationship.\r
+      //\r
+      Status = NetLibCreateServiceChild (\r
+                 ControllerHandle,\r
+                 This->DriverBindingHandle,\r
+                 &gEfiTcp4ServiceBindingProtocolGuid,\r
+                 &HttpService->Tcp4ChildHandle\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+      \r
+      Status = gBS->OpenProtocol (\r
+                      HttpService->Tcp4ChildHandle,\r
+                      &gEfiTcp4ProtocolGuid,\r
+                      &Interface,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                      );\r
+                      \r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+      \r
+    } else {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+\r
+  } else {\r
+    UsingIpv6 = TRUE;\r
+    \r
+    if (HttpService->Tcp6ChildHandle == NULL) {\r
+      //\r
+      // Create a TCP6 child instance, but do not configure it. This will establish the parent-child relationship.\r
+      //\r
+      Status = NetLibCreateServiceChild (\r
+                 ControllerHandle,\r
+                 This->DriverBindingHandle,\r
+                 &gEfiTcp6ServiceBindingProtocolGuid,\r
+                 &HttpService->Tcp6ChildHandle\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+      \r
+      Status = gBS->OpenProtocol (\r
+                      HttpService->Tcp6ChildHandle,\r
+                      &gEfiTcp6ProtocolGuid,\r
+                      &Interface,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                      );\r
+                      \r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+      \r
+    } else {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+  \r
+ON_ERROR:\r
+    \r
+  if (HttpService != NULL) {\r
+    HttpCleanService (HttpService, UsingIpv6);\r
+    if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) {\r
+      FreePool (HttpService);\r
+    }\r
+  }\r
+      \r
+  return Status;\r
+\r
+\r
+}\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. This is the worker function for\r
+  HttpDxeIp4(6)DriverBindingStop.\r
+\r
+  @param[in]  This              Protocol instance pointer.\r
+  @param[in]  ControllerHandle  Handle of device to stop driver on.\r
+  @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                                children is zero stop the entire bus driver.\r
+  @param[in]  ChildHandleBuffer List of Child Handles to Stop.\r
+  @param[in]  IpVersion         IP_VERSION_4 or IP_VERSION_6.\r
+\r
+  @retval EFI_SUCCESS           This driver was removed ControllerHandle.\r
+  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
+  @retval Others                This driver was not removed from this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer,\r
+  IN UINT8                        IpVersion\r
+  )\r
+{\r
+  EFI_HANDLE                                 NicHandle;\r
+  EFI_STATUS                                 Status;\r
+  EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;\r
+  HTTP_SERVICE                               *HttpService;\r
+  LIST_ENTRY                                 *List;\r
+  HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT   Context;\r
+  BOOLEAN                                    UsingIpv6;\r
+\r
+  //\r
+  // HTTP driver opens TCP4(6) child, So, Controller is a TCP4(6)\r
+  // child handle. Locate the Nic handle first. Then get the\r
+  // HTTP private data back.\r
+  //\r
+  if (IpVersion == IP_VERSION_4) {\r
+    UsingIpv6 = FALSE;\r
+    NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);\r
+  } else {\r
+    UsingIpv6 = TRUE;\r
+    NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid);\r
+  }\r
+\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  NicHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    \r
+    HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
+    \r
+    if (NumberOfChildren != 0) {\r
+      //\r
+      // Destroy the HTTP child instance in ChildHandleBuffer.\r
+      //\r
+      List = &HttpService->ChildrenList;\r
+      Context.ServiceBinding    = ServiceBinding;\r
+      Context.NumberOfChildren  = NumberOfChildren;\r
+      Context.ChildHandleBuffer = ChildHandleBuffer;\r
+      Status = NetDestroyLinkList (\r
+                 List,\r
+                 HttpDestroyChildEntryInHandleBuffer,\r
+                 &Context,\r
+                 NULL\r
+                 );\r
+    } else {\r
+    \r
+      HttpCleanService (HttpService, UsingIpv6);\r
+      \r
+      if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) {\r
+        gBS->UninstallProtocolInterface (\r
+               NicHandle,\r
+               &gEfiHttpServiceBindingProtocolGuid,\r
+               ServiceBinding\r
+               );\r
+        FreePool (HttpService);\r
+      }\r
+      Status = EFI_SUCCESS;\r
+    }  \r
+  }\r
+  \r
+  return Status;\r
+\r
+}\r
+\r
 /**\r
   Tests to see if this driver supports a given controller. If a child device is provided, \r
   it further tests to see if this driver supports creating a handle for the specified child device.\r
@@ -267,41 +632,18 @@ HttpDestroyChildEntryInHandleBuffer (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingSupported (\r
+HttpDxeIp4DriverBindingSupported (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
-  EFI_STATUS       Status;\r
-\r
-  //\r
-  // Test for the HttpServiceBinding protocol.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  ControllerHandle,\r
-                  &gEfiHttpServiceBindingProtocolGuid,\r
-                  NULL,\r
-                  This->DriverBindingHandle,\r
-                  ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                  );\r
-  if (!EFI_ERROR (Status)) {\r
-    return EFI_ALREADY_STARTED;\r
-  }\r
-\r
-  //\r
-  // Test for the Tcp4 Protocol\r
-  //\r
-  return gBS->OpenProtocol (\r
-                ControllerHandle,\r
-                &gEfiTcp4ServiceBindingProtocolGuid,\r
-                NULL,\r
-                This->DriverBindingHandle,\r
-                ControllerHandle,\r
-                EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                );\r
-  \r
+  return HttpDxeSupported (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_4\r
+           );\r
 }\r
 \r
 /**\r
@@ -342,90 +684,173 @@ HttpDxeDriverBindingSupported (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingStart (\r
+HttpDxeIp4DriverBindingStart (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
-  EFI_STATUS                      Status;\r
-  HTTP_SERVICE                    *HttpService;\r
-  VOID                            *Interface;\r
+  return HttpDxeStart (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_4\r
+           );\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
   \r
-  //\r
-  // Test for the Http service binding protocol\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  ControllerHandle,\r
-                  &gEfiHttpServiceBindingProtocolGuid,\r
-                  NULL,\r
-                  This->DriverBindingHandle,\r
-                  ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                  );\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
 \r
-  if (Status == EFI_SUCCESS) {\r
-    return EFI_ALREADY_STARTED;\r
-  }\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
 \r
-  Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp4DriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
+  )\r
+{\r
+  return HttpDxeStop (\r
+           This,\r
+           ControllerHandle,\r
+           NumberOfChildren,\r
+           ChildHandleBuffer,\r
+           IP_VERSION_4\r
+           );\r
+}\r
 \r
-  ASSERT (HttpService != NULL);\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
 \r
-  //\r
-  // Create a TCP child instance, but do not configure it. This will establish the parent-child relationship.\r
-  //\r
-  Status = NetLibCreateServiceChild (\r
-             ControllerHandle,\r
-             This->DriverBindingHandle,\r
-             &gEfiTcp4ServiceBindingProtocolGuid,\r
-             &HttpService->TcpChildHandle\r
-             );\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
 \r
-  Status = gBS->OpenProtocol (\r
-                  HttpService->TcpChildHandle,\r
-                  &gEfiTcp4ProtocolGuid,\r
-                  &Interface,\r
-                  This->DriverBindingHandle,\r
-                  ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                  );\r
-                  \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp6DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{  \r
+  return HttpDxeSupported (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_6\r
+           );\r
 \r
-  //\r
-  // Install the HttpServiceBinding Protocol onto Controller\r
-  //\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &ControllerHandle,\r
-                  &gEfiHttpServiceBindingProtocolGuid,\r
-                  &HttpService->ServiceBinding,\r
-                  NULL\r
-                  );\r
+}\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+/**\r
+  Starts a device controller or a bus controller.\r
 \r
-  return EFI_SUCCESS;\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
 \r
-ON_ERROR:\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
 \r
-  if (HttpService != NULL) {\r
-    HttpCleanService (HttpService);\r
-    FreePool (HttpService);\r
-  }\r
-  \r
-  return Status;\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_ALREADY_STARTED      This device is already running on ControllerHandle.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp6DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  return HttpDxeStart (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_6\r
+           );\r
 }\r
 \r
 /**\r
@@ -456,78 +881,21 @@ ON_ERROR:
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingStop (\r
+HttpDxeIp6DriverBindingStop (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN UINTN                        NumberOfChildren,\r
   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
   )\r
 {\r
-  EFI_HANDLE                                 NicHandle;\r
-  EFI_STATUS                                 Status;\r
-  EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;\r
-  HTTP_SERVICE                               *HttpService;\r
-  LIST_ENTRY                                 *List;\r
-  HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT   Context;\r
-  \r
-  //\r
-  // HTTP driver opens TCP child, So, Controller is a TCP\r
-  // child handle. Locate the Nic handle first. Then get the\r
-  // HTTP private data back.\r
-  //\r
-  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);\r
-  if (NicHandle == NULL) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  Status = gBS->OpenProtocol (\r
-                  NicHandle,\r
-                  &gEfiHttpServiceBindingProtocolGuid,\r
-                  (VOID **) &ServiceBinding,\r
-                  This->DriverBindingHandle,\r
-                  NicHandle,\r
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
-\r
-  if (!IsListEmpty (&HttpService->ChildrenList)) {\r
-    //\r
-    // Destroy the HTTP child instance in ChildHandleBuffer.\r
-    //\r
-    List = &HttpService->ChildrenList;\r
-    Context.ServiceBinding    = ServiceBinding;\r
-    Context.NumberOfChildren  = NumberOfChildren;\r
-    Context.ChildHandleBuffer = ChildHandleBuffer;\r
-    Status = NetDestroyLinkList (\r
-               List,\r
-               HttpDestroyChildEntryInHandleBuffer,\r
-               &Context,\r
-               NULL\r
-               );\r
-  }\r
-\r
-  if (NumberOfChildren == 0 && IsListEmpty (&HttpService->ChildrenList)) {\r
-    gBS->UninstallProtocolInterface (\r
-           NicHandle,\r
-           &gEfiHttpServiceBindingProtocolGuid,\r
-           ServiceBinding\r
+  return HttpDxeStop (\r
+           This,\r
+           ControllerHandle,\r
+           NumberOfChildren,\r
+           ChildHandleBuffer,\r
+           IP_VERSION_6\r
            );\r
-\r
-    HttpCleanService (HttpService);\r
-   \r
-    FreePool (HttpService);\r
-\r
-    Status = EFI_SUCCESS;\r
-  }\r
-\r
-  return Status;\r
 }\r
-\r
 /**\r
   Creates a child handle and installs a protocol.\r
 \r
@@ -557,7 +925,6 @@ HttpServiceBindingCreateChild (
   HTTP_SERVICE         *HttpService;\r
   HTTP_PROTOCOL        *HttpInstance;\r
   EFI_STATUS           Status;\r
-  VOID                 *Interface;\r
   EFI_TPL              OldTpl;\r
 \r
   if ((This == NULL) || (ChildHandle == NULL)) {\r
@@ -569,6 +936,12 @@ HttpServiceBindingCreateChild (
   if (HttpInstance == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+  \r
+  HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;\r
+  HttpInstance->Service   = HttpService;\r
+  CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));\r
+  NetMapInit (&HttpInstance->TxTokens);\r
+  NetMapInit (&HttpInstance->RxTokens);\r
 \r
   //\r
   // Install HTTP protocol onto ChildHandle\r
@@ -584,27 +957,7 @@ HttpServiceBindingCreateChild (
     goto ON_ERROR;\r
   }\r
 \r
-  HttpInstance->Handle = *ChildHandle;\r
-\r
-  Status = HttpInitProtocol (HttpService, HttpInstance);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
-\r
-  //\r
-  // Open the default Tcp4 protocol by child.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  HttpService->TcpChildHandle,\r
-                  &gEfiTcp4ProtocolGuid,\r
-                  (VOID **) &Interface,\r
-                  gHttpDxeDriverBinding.DriverBindingHandle,\r
-                  HttpInstance->Handle,\r
-                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+  HttpInstance->Handle    = *ChildHandle;\r
 \r
   //\r
   // Add it to the HTTP service's child list.\r
@@ -619,8 +972,9 @@ HttpServiceBindingCreateChild (
   return EFI_SUCCESS;\r
   \r
 ON_ERROR:\r
-\r
-  HttpCleanProtocol (HttpInstance);\r
\r
+  NetMapClean (&HttpInstance->TxTokens);\r
+  NetMapClean (&HttpInstance->RxTokens);\r
   FreePool (HttpInstance);\r
 \r
   return Status;\r
@@ -664,8 +1018,8 @@ HttpServiceBindingDestroyChild (
                   ChildHandle,\r
                   &gEfiHttpProtocolGuid,\r
                   (VOID **) &Http,\r
-                  gHttpDxeDriverBinding.DriverBindingHandle,\r
-                  ChildHandle,\r
+                  NULL,\r
+                  NULL,\r
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
@@ -681,16 +1035,6 @@ HttpServiceBindingDestroyChild (
     return EFI_SUCCESS;\r
   }\r
 \r
-  //\r
-  // Close the Tcp4 protocol.\r
-  //\r
-  gBS->CloseProtocol (\r
-         HttpService->TcpChildHandle,\r
-         &gEfiTcp4ProtocolGuid,\r
-         gHttpDxeDriverBinding.DriverBindingHandle,\r
-         ChildHandle\r
-         );\r
-  \r
   HttpInstance->InDestroy = TRUE;\r
 \r
   //\r
@@ -706,11 +1050,11 @@ HttpServiceBindingDestroyChild (
     HttpInstance->InDestroy = FALSE;\r
     return Status;\r
   }\r
-\r
-  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
-\r
+  \r
   HttpCleanProtocol (HttpInstance);\r
-\r
+  \r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  \r
   RemoveEntryList (&HttpInstance->Link);\r
   HttpService->ChildrenNumber--;\r
 \r
index eea8d5169e71a20384e050834b26ada07b3438ed..8fda6b2be4706416c3dc1e1e686802dd41b327b9 100644 (file)
 //\r
 #include <Protocol/HttpUtilities.h>\r
 #include <Protocol/Tcp4.h>\r
+#include <Protocol/Tcp6.h>\r
 #include <Protocol/Dns4.h>\r
+#include <Protocol/Dns6.h>\r
 #include <Protocol/Ip4Config2.h>\r
+#include <Protocol/Ip6Config.h>\r
+\r
 \r
 //\r
 // Produced Protocols\r
@@ -59,7 +63,9 @@
 //\r
 // Protocol instances\r
 //\r
-extern EFI_DRIVER_BINDING_PROTOCOL  gHttpDxeDriverBinding;\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gHttpDxeIp4DriverBinding;\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gHttpDxeIp6DriverBinding;\r
+\r
 extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2;\r
 extern EFI_COMPONENT_NAME_PROTOCOL  gHttpDxeComponentName;\r
 \r
@@ -123,7 +129,7 @@ typedef struct {
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingSupported (\r
+HttpDxeIp4DriverBindingSupported (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
@@ -166,7 +172,7 @@ HttpDxeDriverBindingSupported (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingStart (\r
+HttpDxeIp4DriverBindingStart (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
@@ -200,13 +206,142 @@ HttpDxeDriverBindingStart (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-HttpDxeDriverBindingStop (\r
+HttpDxeIp4DriverBindingStop (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN  EFI_HANDLE                  ControllerHandle,\r
   IN  UINTN                       NumberOfChildren,\r
   IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL\r
   );\r
 \r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp6DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_ALREADY_STARTED      This device is already running on ControllerHandle.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp6DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeIp6DriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
+  );\r
+\r
 /**\r
   Creates a child handle and installs a protocol.\r
 \r
index 0d3bd00cf7b7d0579af08aeeca2cd75a949773c9..bf2cbee5f7c978e9a9c02ee0b444b485d1957304 100644 (file)
   gEfiHttpUtilitiesProtocolGuid                    ## CONSUMES\r
   gEfiTcp4ServiceBindingProtocolGuid               ## TO_START\r
   gEfiTcp4ProtocolGuid                             ## TO_START\r
+  gEfiTcp6ServiceBindingProtocolGuid               ## TO_START\r
+  gEfiTcp6ProtocolGuid                             ## TO_START\r
   gEfiDns4ServiceBindingProtocolGuid               ## SOMETIMES_CONSUMES\r
   gEfiDns4ProtocolGuid                             ## SOMETIMES_CONSUMES\r
+  gEfiDns6ServiceBindingProtocolGuid               ## SOMETIMES_CONSUMES\r
+  gEfiDns6ProtocolGuid                             ## SOMETIMES_CONSUMES\r
   gEfiIp4Config2ProtocolGuid                       ## SOMETIMES_CONSUMES\r
+  gEfiIp6ConfigProtocolGuid                        ## SOMETIMES_CONSUMES\r
 \r
 [UserExtensions.TianoCore."ExtraFiles"]\r
   HttpDxeExtra.uni
\ No newline at end of file
index f9c2ac812e573faa9e5ff1e6d2ecd630be2ff395..d6792dd41eb4c2642d65eb7e01c0833b43f92761 100644 (file)
Binary files a/NetworkPkg/HttpDxe/HttpDxe.uni and b/NetworkPkg/HttpDxe/HttpDxe.uni differ
index f1e3e5341136b28b5a0ee962041deb806af254a2..c527da08723ece2c4878f64c357ef20e4462998d 100644 (file)
@@ -51,6 +51,8 @@ EfiHttpGetModeData (
   )\r
 {\r
   HTTP_PROTOCOL                 *HttpInstance;\r
+  EFI_HTTPv4_ACCESS_POINT       *Http4AccessPoint;\r
+  EFI_HTTPv6_ACCESS_POINT       *Http6AccessPoint;\r
 \r
   if ((This == NULL) || (HttpConfigData == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -58,24 +60,32 @@ EfiHttpGetModeData (
   \r
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
-\r
+  \r
   if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
     return EFI_NOT_STARTED;\r
   }\r
 \r
-  if (HttpConfigData->AccessPoint.IPv4Node == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
   HttpConfigData->HttpVersion        = HttpInstance->HttpVersion;\r
   HttpConfigData->TimeOutMillisec    = HttpInstance->TimeOutMillisec;\r
   HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;\r
 \r
-  CopyMem (\r
-    HttpConfigData->AccessPoint.IPv4Node,\r
-    &HttpInstance->IPv4Node,\r
-    sizeof (HttpInstance->IPv4Node)\r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));\r
+    CopyMem (\r
+      Http6AccessPoint,\r
+      &HttpInstance->Ipv6Node,\r
+      sizeof (HttpInstance->Ipv6Node)\r
     );\r
+    HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint;\r
+  } else {\r
+    Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));\r
+    CopyMem (\r
+      Http4AccessPoint,\r
+      &HttpInstance->IPv4Node,\r
+      sizeof (HttpInstance->IPv4Node)\r
+      );\r
+    HttpConfigData->AccessPoint.IPv4Node = Http4AccessPoint;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -120,8 +130,13 @@ EfiHttpConfigure (
 {\r
   HTTP_PROTOCOL                 *HttpInstance;\r
   EFI_STATUS                    Status;\r
-\r
-  if (This == NULL) {\r
+  \r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (This == NULL || \r
+     (HttpConfigData != NULL && ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+                                 (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -129,18 +144,7 @@ EfiHttpConfigure (
   ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);\r
 \r
   if (HttpConfigData != NULL) {\r
-    //\r
-    // Check input parameters.\r
-    //\r
-    if (HttpConfigData->LocalAddressIsIPv6) {\r
-      if (HttpConfigData->AccessPoint.IPv6Node == NULL) {\r
-        return EFI_INVALID_PARAMETER;\r
-      }\r
-    } else {\r
-      if (HttpConfigData->AccessPoint.IPv4Node == NULL) {\r
-        return EFI_INVALID_PARAMETER;\r
-      }\r
-    }\r
+\r
     //\r
     // Now configure this HTTP instance.\r
     //\r
@@ -151,33 +155,38 @@ EfiHttpConfigure (
     HttpInstance->HttpVersion        = HttpConfigData->HttpVersion;\r
     HttpInstance->TimeOutMillisec    = HttpConfigData->TimeOutMillisec;\r
     HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;\r
-\r
-    if (HttpConfigData->LocalAddressIsIPv6) {\r
-      return EFI_UNSUPPORTED;\r
+    \r
+    if (HttpConfigData->LocalAddressIsIPv6) { \r
+      CopyMem (\r
+        &HttpInstance->Ipv6Node,\r
+        HttpConfigData->AccessPoint.IPv6Node,\r
+        sizeof (HttpInstance->Ipv6Node)\r
+        );\r
     } else {\r
       CopyMem (\r
         &HttpInstance->IPv4Node,\r
         HttpConfigData->AccessPoint.IPv4Node,\r
         sizeof (HttpInstance->IPv4Node)\r
         );\r
-\r
-      HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
-      return EFI_SUCCESS;\r
     }\r
+    //\r
+    // Creat Tcp child\r
+    //\r
+    Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
+    return EFI_SUCCESS;\r
 \r
   } else {\r
-    if (HttpInstance->LocalAddressIsIPv6) {\r
-      return EFI_UNSUPPORTED;\r
-    } else {\r
-      HttpCleanProtocol (HttpInstance);\r
-      Status = HttpInitProtocol (HttpInstance->Service, HttpInstance);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      HttpInstance->State = HTTP_STATE_UNCONFIGED;\r
-      return EFI_SUCCESS;\r
-    }\r
+    //\r
+    // Reset all the resources related to HttpInsance.\r
+    //\r
+    HttpCleanProtocol (HttpInstance);\r
+    HttpInstance->State = HTTP_STATE_UNCONFIGED;\r
+    return EFI_SUCCESS;\r
   }\r
 }\r
  \r
@@ -264,10 +273,6 @@ EfiHttpRequest (
     return EFI_NOT_STARTED;\r
   }\r
 \r
-  if (HttpInstance->LocalAddressIsIPv6) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
   //\r
   // Check whether the token already existed.\r
   //\r
@@ -291,7 +296,8 @@ EfiHttpRequest (
     }\r
     FreePool (HttpInstance->Url);\r
     HttpInstance->Url = Url;    \r
-  }  \r
+  } \r
+\r
 \r
   UnicodeStrToAsciiStr (Request->Url, Url);\r
   UrlParser = NULL;\r
@@ -340,7 +346,7 @@ EfiHttpRequest (
         Wrap->HttpToken    = Token;\r
         Wrap->HttpInstance = HttpInstance;\r
 \r
-        Status = HttpCreateTcp4TxEvent (Wrap);\r
+        Status = HttpCreateTcpTxEvent (Wrap);\r
         if (EFI_ERROR (Status)) {\r
           goto Error1;\r
         }\r
@@ -379,24 +385,35 @@ EfiHttpRequest (
 \r
   if (Configure) {\r
     //\r
-    // Parse Url for IPv4 address, if failed, perform DNS resolution.\r
+    // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution.\r
     //\r
-    Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
+    } else {\r
+      Status = NetLibAsciiStrToIp6 (HostName, &HttpInstance->RemoteIpv6Addr);\r
+    }\r
+\r
     if (EFI_ERROR (Status)) {\r
-      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16));\r
+      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
       if (HostNameStr == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Error1;\r
       }\r
-\r
+      \r
       AsciiStrToUnicodeStr (HostName, HostNameStr);\r
-      Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
+      if (!HttpInstance->LocalAddressIsIPv6) {\r
+        Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
+      } else {\r
+        Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);\r
+      }\r
+      \r
       FreePool (HostNameStr);\r
       if (EFI_ERROR (Status)) {\r
         goto Error1;\r
       }\r
     }\r
 \r
+\r
     //\r
     // Save the RemotePort and RemoteHost.\r
     //\r
@@ -410,7 +427,7 @@ EfiHttpRequest (
     //\r
     // The request URL is different from previous calls to Request(), close existing TCP instance.\r
     //\r
-    ASSERT (HttpInstance->Tcp4 != NULL);\r
+    ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL);\r
     HttpCloseConnection (HttpInstance);\r
     EfiHttpCancel (This, NULL);\r
   }\r
@@ -429,25 +446,16 @@ EfiHttpRequest (
   Wrap->TcpWrap.Method = Request->Method;\r
 \r
   if (Configure) {\r
-    //\r
-    // Configure TCP instance.\r
-    //\r
-    Status = HttpConfigureTcp4 (HttpInstance, Wrap);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error1;\r
-    }\r
-    //\r
-    // Connect TCP.\r
-    //\r
-    Status = HttpConnectTcp4 (HttpInstance);\r
+    Status = HttpInitTcp (HttpInstance, Wrap);\r
     if (EFI_ERROR (Status)) {\r
       goto Error2;\r
     }\r
+\r
   } else {\r
     //\r
     // For the new HTTP token, create TX TCP token events.    \r
     //\r
-    Status = HttpCreateTcp4TxEvent (Wrap);\r
+    Status = HttpCreateTcpTxEvent (Wrap);\r
     if (EFI_ERROR (Status)) {\r
       goto Error1;\r
     }\r
@@ -488,7 +496,7 @@ EfiHttpRequest (
   //\r
   // Transmit the request message.\r
   //\r
-  Status = HttpTransmitTcp4 (\r
+  Status = HttpTransmitTcp (\r
              HttpInstance,\r
              Wrap,\r
              (UINT8*) RequestStr,\r
@@ -499,11 +507,11 @@ EfiHttpRequest (
   }\r
 \r
   DispatchDpc ();\r
-\r
+  \r
   if (HostName != NULL) {\r
     FreePool (HostName);\r
   }\r
-\r
+  \r
   return EFI_SUCCESS;\r
 \r
 Error5:\r
@@ -517,15 +525,19 @@ Error4:
 Error3:\r
   HttpCloseConnection (HttpInstance);\r
 \r
-\r
 Error2:\r
-  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
-  if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) {\r
-    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
-    Wrap->TcpWrap.TxToken.CompletionToken.Event = NULL;\r
+  HttpCloseTcpConnCloseEvent (HttpInstance);\r
+  if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
+    Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL;\r
+  }\r
+  if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+    Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL;\r
   }\r
 \r
 Error1:\r
+\r
   if (HostName != NULL) {\r
     FreePool (HostName);\r
   }\r
@@ -541,7 +553,7 @@ Error1:
 }\r
 \r
 /**\r
-  Cancel a TxToken or RxToken. \r
+  Cancel a user's Token. \r
  \r
   @param[in]  Map                The HTTP instance's token queue.\r
   @param[in]  Item               Object container for one HTTP token and token's wrap.\r
@@ -562,6 +574,7 @@ HttpCancelTokens (
 \r
   EFI_HTTP_TOKEN            *Token;\r
   HTTP_TOKEN_WRAP           *Wrap;\r
+  HTTP_PROTOCOL             *HttpInstance;\r
 \r
   Token = (EFI_HTTP_TOKEN *) Context;\r
 \r
@@ -575,24 +588,41 @@ HttpCancelTokens (
 \r
   Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
   ASSERT (Wrap != NULL);\r
+  HttpInstance = Wrap->HttpInstance;\r
 \r
   //\r
   // Free resources.\r
   //\r
   NetMapRemoveItem (Map, Item, NULL); \r
   \r
-  if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
-  }\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
+    }\r
+    \r
+    if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+    }\r
+    \r
+    if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    }\r
 \r
-  if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
-  }\r
+  } else {\r
+    if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+    }\r
+\r
+    if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
+    }\r
 \r
-  if (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
-    FreePool (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    }\r
   }\r
 \r
+\r
   FreePool (Wrap);\r
 \r
   //\r
@@ -747,7 +777,7 @@ HttpBodyParserCallback (
   Wrap->HttpInstance->NextMsg = Data;\r
 \r
   //\r
-  // Free TxToken since already received corrsponding HTTP response.\r
+  // Free Tx4Token or Tx6Token since already received corrsponding HTTP response.\r
   //\r
   FreePool (Wrap);\r
 \r
@@ -761,7 +791,7 @@ HttpBodyParserCallback (
 \r
   @retval EFI_SUCCESS             Allocation succeeded.\r
   @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.\r
-  @retval EFI_NOT_READY           Can't find a corresponding TxToken or \r
+  @retval EFI_NOT_READY           Can't find a corresponding Tx4Token/Tx6Token or \r
                                   the EFI_HTTP_UTILITIES_PROTOCOL is not available.\r
 \r
 **/\r
@@ -772,12 +802,9 @@ HttpResponseWorker (
 {\r
   EFI_STATUS                    Status;\r
   EFI_HTTP_MESSAGE              *HttpMsg;\r
-  EFI_TCP4_IO_TOKEN             *RxToken;\r
-  EFI_TCP4_PROTOCOL             *Tcp4;\r
   CHAR8                         *EndofHeader;\r
   CHAR8                         *HttpHeaders;\r
   UINTN                         SizeofHeaders;\r
-  CHAR8                         *Buffer;\r
   UINTN                         BufferSize;\r
   UINTN                         StatusCode;\r
   CHAR8                         *Tmp;\r
@@ -796,23 +823,21 @@ HttpResponseWorker (
   \r
   HttpInstance = Wrap->HttpInstance;\r
   Token = Wrap->HttpToken;\r
-\r
   HttpMsg = Token->Message;\r
 \r
-  Tcp4 = HttpInstance->Tcp4;\r
-  ASSERT (Tcp4 != NULL);\r
-  HttpMsg->Headers = NULL;\r
-  HttpHeaders   = NULL;\r
-  SizeofHeaders = 0;\r
-  Buffer        = NULL;\r
-  BufferSize    = 0;\r
-  EndofHeader   = NULL;\r
+  HttpInstance->EndofHeader = NULL;\r
+  HttpInstance->HttpHeaders = NULL;\r
+  HttpMsg->Headers          = NULL;\r
+  HttpHeaders               = NULL;\r
+  SizeofHeaders             = 0;\r
+  BufferSize                = 0;\r
+  EndofHeader               = NULL;\r
  \r
   if (HttpMsg->Data.Response != NULL) {\r
     //\r
     // Need receive the HTTP headers, prepare buffer.\r
     //\r
-    Status = HttpCreateTcp4RxEventForHeader (HttpInstance);\r
+    Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
@@ -843,70 +868,15 @@ HttpResponseWorker (
       // Check whether we cached the whole HTTP headers.\r
       //\r
       EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
-    }\r
-    \r
-    RxToken = &HttpInstance->RxToken;\r
-    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
-    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto Error;\r
-    }\r
-\r
-    //\r
-    // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
-    //\r
-    while (EndofHeader == NULL) {   \r
-      HttpInstance->IsRxDone = FALSE;\r
-      RxToken->Packet.RxData->DataLength = DEF_BUF_LEN;\r
-      RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
-      Status = Tcp4->Receive (Tcp4, RxToken);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
-        goto Error;\r
-      }\r
-      \r
-      while (!HttpInstance->IsRxDone) {\r
-       Tcp4->Poll (Tcp4);\r
-      }    \r
-\r
-      Status = RxToken->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        goto Error;\r
-      }\r
-\r
-      //\r
-      // Append the response string.\r
-      //\r
-      BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength;\r
-      Buffer = AllocateZeroPool (BufferSize);\r
-      if (Buffer == NULL) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
-        goto Error;\r
-      }\r
-\r
-      if (HttpHeaders != NULL) {\r
-        CopyMem (Buffer, HttpHeaders, SizeofHeaders);\r
-        FreePool (HttpHeaders);\r
-      }\r
-\r
-      CopyMem (\r
-        Buffer + SizeofHeaders,\r
-        RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
-        RxToken->Packet.RxData->FragmentTable[0].FragmentLength\r
-        );\r
-      HttpHeaders   = Buffer;\r
-      SizeofHeaders = BufferSize;\r
+    }   \r
 \r
-      //\r
-      // Check whether we received end of HTTP headers.\r
-      //\r
-      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
-    };\r
+    HttpInstance->EndofHeader = &EndofHeader;\r
+    HttpInstance->HttpHeaders = &HttpHeaders;\r
 \r
-    //\r
-    // Skip the CRLF after the HTTP headers.\r
-    //\r
-    EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);\r
+    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
 \r
     //\r
     // Cache the part of body.\r
@@ -927,9 +897,6 @@ HttpResponseWorker (
       HttpInstance->CacheLen = BodyLen;\r
     }\r
 \r
-    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
-\r
     //\r
     // Search for Status Code.\r
     //\r
@@ -997,7 +964,7 @@ HttpResponseWorker (
     }\r
 \r
     //\r
-    // The first TxToken not transmitted yet, insert back and return error.\r
+    // The first Tx Token not transmitted yet, insert back and return error.\r
     //\r
     if (!ValueInItem->TcpWrap.IsTxDone) {\r
       goto Error2;\r
@@ -1108,16 +1075,8 @@ HttpResponseWorker (
   //\r
   // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
   //\r
-  RxToken = &Wrap->TcpWrap.RxToken;\r
-\r
-  RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;\r
-  RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;\r
-  RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;\r
-\r
-  RxToken->CompletionToken.Status = EFI_NOT_READY;\r
-  Status = Tcp4->Receive (Tcp4, RxToken);\r
+  Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
     goto Error;\r
   }\r
 \r
@@ -1130,18 +1089,7 @@ Exit:
   }\r
   Token->Status = Status;\r
   gBS->SignalEvent (Token->Event);\r
-\r
-  if (Wrap != NULL) {\r
-    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
-    }\r
-  }\r
-  \r
-  if (HttpInstance->RxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event);\r
-    HttpInstance->RxToken.CompletionToken.Event = NULL;\r
-  }  \r
-  \r
+  HttpCloseTcpRxEvent (Wrap);\r
   FreePool (Wrap);\r
   return Status;\r
 \r
@@ -1149,28 +1097,7 @@ Error2:
   NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
 \r
 Error:\r
-  if (Wrap != NULL) {\r
-    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
-    }\r
-    RxToken = &Wrap->TcpWrap.RxToken;\r
-    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
-      FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-      RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
-    }\r
-    FreePool (Wrap);\r
-  }\r
-\r
-  if (HttpInstance->RxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event);\r
-    HttpInstance->RxToken.CompletionToken.Event = NULL;\r
-  }\r
-\r
-  RxToken = &HttpInstance->RxToken;\r
-  if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
-    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
-  }\r
+  HttpTcpTokenCleanup (Wrap);\r
   \r
   if (HttpHeaders != NULL) {\r
     FreePool (HttpHeaders);\r
@@ -1268,10 +1195,6 @@ EfiHttpResponse (
     return EFI_NOT_STARTED;\r
   }\r
 \r
-  if (HttpInstance->LocalAddressIsIPv6) {\r
-    return EFI_UNSUPPORTED;\r
-  }  \r
-\r
   //\r
   // Check whether the token already existed.\r
   //\r
@@ -1287,7 +1210,7 @@ EfiHttpResponse (
   Wrap->HttpInstance = HttpInstance;\r
   Wrap->HttpToken    = Token;\r
 \r
-  Status = HttpCreateTcp4RxEvent (Wrap);\r
+  Status = HttpCreateTcpRxEvent (Wrap);\r
   if (EFI_ERROR (Status)) {\r
     goto Error;\r
   }\r
@@ -1308,8 +1231,12 @@ EfiHttpResponse (
 \r
 Error:\r
   if (Wrap != NULL) {\r
-    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
+    if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+    }\r
+\r
+    if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
     }\r
     FreePool (Wrap);\r
   }  \r
@@ -1343,8 +1270,8 @@ EfiHttpPoll (
   IN  EFI_HTTP_PROTOCOL         *This\r
   )\r
 {\r
-  HTTP_PROTOCOL                 *HttpInstance;\r
   EFI_STATUS                    Status;\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1353,17 +1280,18 @@ EfiHttpPoll (
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
 \r
-  if (HttpInstance->LocalAddressIsIPv6) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  if (HttpInstance->Tcp4 == NULL || HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && \r
+                                                          HttpInstance->Tcp6 == NULL)) {\r
     return EFI_NOT_STARTED;\r
   }\r
-\r
-  Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
-\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+  } else {\r
+    Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+  }\r
+  \r
   DispatchDpc ();\r
-\r
\r
   return Status;\r
 }\r
index 57ea2073893dfc69e195bdea246d1dcd23dca10d..39837a3c827dd53d5a13fd096db070cc329f77c5 100644 (file)
@@ -37,7 +37,7 @@ HttpCommonNotify (
 }\r
 \r
 /**\r
-  The notify function associated with TxToken for Tcp4->Transmit().\r
+  The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().\r
 \r
   @param[in]  Context The context.\r
 \r
@@ -49,25 +49,46 @@ HttpTcpTransmitNotifyDpc (
   )\r
 {\r
   HTTP_TOKEN_WRAP          *Wrap;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
 \r
   if (Context == NULL) {\r
     return ;\r
   }\r
+  \r
+  Wrap         = (HTTP_TOKEN_WRAP *) Context;\r
+  HttpInstance = Wrap->HttpInstance;\r
+  \r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+      Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;\r
+      gBS->SignalEvent (Wrap->HttpToken->Event);\r
+\r
+      //\r
+      // Free resources.\r
+      //\r
+      if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+        FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);\r
+      }\r
 \r
-  Wrap = (HTTP_TOKEN_WRAP *) Context;\r
-  Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status;\r
-  gBS->SignalEvent (Wrap->HttpToken->Event);\r
+      if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {\r
+        gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
+      }\r
+      \r
+  } else {\r
+    Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;\r
+    gBS->SignalEvent (Wrap->HttpToken->Event);\r
+    \r
+    //\r
+    // Free resources.\r
+    //\r
+    if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);\r
+    }\r
 \r
-  //\r
-  // Free resources.\r
-  //\r
-  if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {\r
-    FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer);\r
+    if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+    }   \r
   }\r
 \r
-  if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
-  }\r
 \r
   Wrap->TcpWrap.IsTxDone = TRUE;\r
 \r
@@ -98,9 +119,8 @@ HttpTcpTransmitNotify (
   QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);\r
 }\r
 \r
-\r
 /**\r
-  The notify function associated with RxToken for Tcp4->Receive ().\r
+  The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().\r
 \r
   @param[in]  Context The context.\r
 \r
@@ -116,25 +136,41 @@ HttpTcpReceiveNotifyDpc (
   UINTN                    Length;\r
   EFI_STATUS               Status;\r
   HTTP_PROTOCOL            *HttpInstance;\r
+  BOOLEAN                  UsingIpv6;\r
 \r
   if (Context == NULL) {\r
     return ;\r
   }\r
 \r
   Wrap = (HTTP_TOKEN_WRAP *) Context;\r
-  gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
-  if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) {\r
-    return ;\r
-  }\r
-\r
   HttpInstance = Wrap->HttpInstance;\r
+  UsingIpv6    = HttpInstance->LocalAddressIsIPv6;\r
+  \r
+  if (UsingIpv6) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
+    \r
+    if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {\r
+      return ;\r
+    }\r
+\r
+  } else {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+    \r
+    if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {\r
+      return ;\r
+    }\r
+  }\r
 \r
   //\r
   // Check whether we receive a complete HTTP message.\r
   //\r
   ASSERT (HttpInstance->MsgParser != NULL);\r
+  if (UsingIpv6) {\r
+    Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;\r
+  } else {\r
+    Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;\r
+  }\r
 \r
-  Length = (UINTN) Wrap->TcpWrap.RxData.FragmentTable[0].FragmentLength;\r
   Status = HttpParseMessageBody (\r
              HttpInstance->MsgParser,\r
              Length,\r
@@ -179,7 +215,12 @@ HttpTcpReceiveNotifyDpc (
 \r
 \r
   Wrap->TcpWrap.IsRxDone = TRUE;\r
-  Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status;\r
+  if (UsingIpv6) {\r
+    Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;\r
+  } else {\r
+    Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;\r
+  }\r
+  \r
 \r
   gBS->SignalEvent (Wrap->HttpToken->Event);\r
 \r
@@ -211,9 +252,8 @@ HttpTcpReceiveNotify (
   QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);\r
 }\r
 \r
-\r
 /**\r
-  Create events for the TCP4 connection token and TCP4 close token.\r
+  Create events for the TCP connection token and TCP close token.\r
 \r
   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
 \r
@@ -222,11 +262,13 @@ HttpTcpReceiveNotify (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4ConnCloseEvent (\r
+HttpCreateTcpConnCloseEvent (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   )\r
 {\r
   EFI_STATUS               Status;\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
     //\r
     // Create events for variuos asynchronous operations.\r
     //\r
@@ -234,66 +276,109 @@ HttpCreateTcp4ConnCloseEvent (
                     EVT_NOTIFY_SIGNAL,\r
                     TPL_NOTIFY,\r
                     HttpCommonNotify,\r
-                    &HttpInstance->IsConnDone,\r
-                    &HttpInstance->ConnToken.CompletionToken.Event\r
+                    &HttpInstance->IsTcp4ConnDone,\r
+                    &HttpInstance->Tcp4ConnToken.CompletionToken.Event\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       goto ERROR;\r
     }\r
 \r
     //\r
-    // Initialize CloseToken\r
+    // Initialize Tcp4CloseToken\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsTcp4CloseDone,\r
+                    &HttpInstance->Tcp4CloseToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+    \r
+  } else {\r
+    //\r
+    // Create events for variuos asynchronous operations.\r
     //\r
     Status = gBS->CreateEvent (\r
                     EVT_NOTIFY_SIGNAL,\r
                     TPL_NOTIFY,\r
                     HttpCommonNotify,\r
-                    &HttpInstance->IsCloseDone,\r
-                    &HttpInstance->CloseToken.CompletionToken.Event\r
+                    &HttpInstance->IsTcp6ConnDone,\r
+                    &HttpInstance->Tcp6ConnToken.CompletionToken.Event\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       goto ERROR;\r
     }\r
 \r
\r
+    //\r
+    // Initialize Tcp6CloseToken\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsTcp6CloseDone,\r
+                    &HttpInstance->Tcp6CloseToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+  }\r
+     \r
   return EFI_SUCCESS;\r
 \r
 ERROR:\r
   //\r
   // Error handling\r
   //\r
-  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
+  HttpCloseTcpConnCloseEvent (HttpInstance);\r
 \r
   return Status;\r
 }\r
 \r
 \r
 /**\r
-  Close events in the TCP4 connection token and TCP4 close token.\r
+  Close events in the TCP connection token and TCP close token.\r
 \r
   @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.\r
 \r
 **/\r
 VOID\r
-HttpCloseTcp4ConnCloseEvent (\r
+HttpCloseTcpConnCloseEvent (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   )\r
 {\r
   ASSERT (HttpInstance != NULL);\r
 \r
-  if (NULL != HttpInstance->ConnToken.CompletionToken.Event) {\r
-    gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event);\r
-    HttpInstance->ConnToken.CompletionToken.Event = NULL;\r
-  }\r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {\r
+      gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);\r
+      HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;\r
+    }\r
 \r
-  if (NULL != HttpInstance->CloseToken.CompletionToken.Event) {\r
-    gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event);\r
-    HttpInstance->CloseToken.CompletionToken.Event = NULL;\r
-  }  \r
+    if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {\r
+      gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);\r
+      HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;\r
+    }\r
+\r
+  } else {\r
+    if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {\r
+      gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);\r
+      HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;\r
+    }\r
+\r
+    if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {\r
+      gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);\r
+      HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;\r
+    }\r
+  }\r
+  \r
 }\r
 \r
 /**\r
-  Create event for the TCP4 transmit token.\r
+  Create event for the TCP transmit token.\r
 \r
   @param[in]  Wrap               Point to HTTP token's wrap data.\r
 \r
@@ -302,37 +387,61 @@ HttpCloseTcp4ConnCloseEvent (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4TxEvent (\r
+HttpCreateTcpTxEvent (\r
   IN  HTTP_TOKEN_WRAP      *Wrap\r
   )\r
 {\r
   EFI_STATUS               Status;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
   HTTP_TCP_TOKEN_WRAP      *TcpWrap;\r
 \r
+  HttpInstance = Wrap->HttpInstance;\r
   TcpWrap      = &Wrap->TcpWrap;\r
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  HttpTcpTransmitNotify,\r
-                  Wrap,\r
-                  &TcpWrap->TxToken.CompletionToken.Event\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpTcpTransmitNotify,\r
+                    Wrap,\r
+                    &TcpWrap->Tx4Token.CompletionToken.Event\r
+                    );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    \r
+      TcpWrap->Tx4Data.Push = TRUE;\r
+      TcpWrap->Tx4Data.Urgent = FALSE;\r
+      TcpWrap->Tx4Data.FragmentCount = 1;\r
+      TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;\r
+      TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;\r
 \r
-  TcpWrap->TxData.Push = TRUE;\r
-  TcpWrap->TxData.Urgent = FALSE;\r
-  TcpWrap->TxData.FragmentCount = 1;\r
-  TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData;\r
-  TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY;\r
+  } else {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpTcpTransmitNotify,\r
+                    Wrap,\r
+                    &TcpWrap->Tx6Token.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
+    TcpWrap->Tx6Data.Push   = TRUE;\r
+    TcpWrap->Tx6Data.Urgent = FALSE;\r
+    TcpWrap->Tx6Data.FragmentCount  = 1;\r
+    TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;\r
+    TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY;\r
+    \r
+    \r
+  }\r
+  \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Create event for the TCP4 receive token which is used to receive HTTP header.\r
+  Create event for the TCP receive token which is used to receive HTTP header.\r
 \r
   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
 \r
@@ -341,33 +450,52 @@ HttpCreateTcp4TxEvent (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4RxEventForHeader (\r
+HttpCreateTcpRxEventForHeader (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   )\r
 {\r
   EFI_STATUS               Status;\r
 \r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsRxDone,\r
+                    &HttpInstance->Rx4Token.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    HttpInstance->Rx4Data.FragmentCount = 1;\r
+    HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;\r
+    HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;\r
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  HttpCommonNotify,\r
-                  &HttpInstance->IsRxDone,\r
-                  &HttpInstance->RxToken.CompletionToken.Event\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  } else {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsRxDone,\r
+                    &HttpInstance->Rx6Token.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    HttpInstance->Rx6Data.FragmentCount  =1;\r
+    HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;\r
+    HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;\r
+    \r
   }\r
 \r
-  HttpInstance->RxData.FragmentCount = 1;\r
-  HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData;\r
-  HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY;\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Create event for the TCP4 receive token which is used to receive HTTP body.\r
+  Create event for the TCP receive token which is used to receive HTTP body.\r
 \r
   @param[in]  Wrap               Point to HTTP token's wrap data.\r
 \r
@@ -376,38 +504,101 @@ HttpCreateTcp4RxEventForHeader (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4RxEvent (\r
+HttpCreateTcpRxEvent (\r
   IN  HTTP_TOKEN_WRAP      *Wrap \r
   )\r
 {\r
   EFI_STATUS               Status;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
   HTTP_TCP_TOKEN_WRAP      *TcpWrap;\r
 \r
+  HttpInstance = Wrap->HttpInstance;\r
   TcpWrap      = &Wrap->TcpWrap;\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpTcpReceiveNotify,\r
+                    Wrap,\r
+                    &TcpWrap->Rx4Token.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    TcpWrap->Rx4Data.FragmentCount = 1;\r
+    TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;\r
+    TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;\r
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  HttpTcpReceiveNotify,\r
-                  Wrap,\r
-                  &TcpWrap->RxToken.CompletionToken.Event\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  } else {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpTcpReceiveNotify,\r
+                    Wrap,\r
+                    &TcpWrap->Rx6Token.CompletionToken.Event\r
+                    );  \r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    TcpWrap->Rx6Data.FragmentCount = 1;\r
+    TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;\r
+    TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;\r
   }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
 \r
-  TcpWrap->RxData.FragmentCount = 1;\r
-  TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData;\r
-  TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY;\r
+/**\r
+  Close Events for Tcp Receive Tokens for HTTP body and HTTP header.\r
 \r
-  return EFI_SUCCESS;\r
+  @param[in]  Wrap               Pointer to HTTP token's wrap data.\r
+  \r
+**/\r
+VOID\r
+HttpCloseTcpRxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  )\r
+{\r
+  HTTP_PROTOCOL            *HttpInstance;\r
+  EFI_TCP4_IO_TOKEN        *Rx4Token;\r
+  EFI_TCP6_IO_TOKEN        *Rx6Token;\r
+\r
+  HttpInstance   = Wrap->HttpInstance;\r
+  Rx4Token       = NULL;\r
+  Rx6Token       = NULL;\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    if (Wrap != NULL) {\r
+      if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+        gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
+      } \r
+    }\r
+\r
+    if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);\r
+      HttpInstance->Rx6Token.CompletionToken.Event = NULL;\r
+    }\r
+  } else {\r
+    if (Wrap != NULL) {\r
+      if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+        gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+      }\r
+    }\r
+    \r
+    if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);\r
+      HttpInstance->Rx4Token.CompletionToken.Event = NULL;\r
+    }\r
+  }\r
 }\r
 \r
 /**\r
   Intiialize the HTTP_PROTOCOL structure to the unconfigured state.\r
 \r
-  @param[in]       HttpSb               The HTTP service private instance.\r
   @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]       IpVersion            Indicate us TCP4 protocol or TCP6 protocol.\r
 \r
   @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.                                          \r
   @retval Others            Other error as indicated.\r
@@ -415,95 +606,198 @@ HttpCreateTcp4RxEvent (
 **/\r
 EFI_STATUS\r
 HttpInitProtocol (\r
-  IN     HTTP_SERVICE            *HttpSb,\r
-  IN OUT HTTP_PROTOCOL           *HttpInstance\r
+  IN OUT HTTP_PROTOCOL           *HttpInstance,\r
+  IN     BOOLEAN                 IpVersion\r
   )\r
 {\r
   EFI_STATUS                     Status;\r
   VOID                           *Interface;\r
+  BOOLEAN                        UsingIpv6;\r
+  \r
+  ASSERT (HttpInstance != NULL);\r
+  UsingIpv6 = IpVersion;\r
+  \r
+  if (!UsingIpv6) {\r
+    //\r
+    // Create TCP4 child.\r
+    //\r
+    Status = NetLibCreateServiceChild (\r
+               HttpInstance->Service->ControllerHandle,\r
+               HttpInstance->Service->ImageHandle,\r
+               &gEfiTcp4ServiceBindingProtocolGuid,\r
+               &HttpInstance->Tcp4ChildHandle\r
+               );\r
 \r
-  ASSERT ((HttpSb != NULL) && (HttpInstance != NULL));\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
 \r
-  HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;\r
-  CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));\r
-  HttpInstance->Service = HttpSb;\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Tcp4ChildHandle,\r
+                    &gEfiTcp4ProtocolGuid,\r
+                    (VOID **) &Interface,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Service->ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    );\r
+                    \r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
 \r
-  //\r
-  // Create TCP child.\r
-  //\r
-  Status = NetLibCreateServiceChild (\r
-             HttpInstance->Service->ControllerHandle,\r
-             HttpInstance->Service->ImageHandle,\r
-             &gEfiTcp4ServiceBindingProtocolGuid,\r
-             &HttpInstance->TcpChildHandle\r
-             );\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Tcp4ChildHandle,\r
+                    &gEfiTcp4ProtocolGuid,\r
+                    (VOID **) &HttpInstance->Tcp4,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      goto ON_ERROR;\r
+    }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Service->Tcp4ChildHandle,\r
+                    &gEfiTcp4ProtocolGuid,\r
+                    (VOID **) &Interface,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  } else {\r
+    //\r
+    // Create TCP6 Child.\r
+    //\r
+    Status = NetLibCreateServiceChild (\r
+               HttpInstance->Service->ControllerHandle,\r
+               HttpInstance->Service->ImageHandle,\r
+               &gEfiTcp6ServiceBindingProtocolGuid,\r
+               &HttpInstance->Tcp6ChildHandle\r
+               );\r
 \r
-  Status = gBS->OpenProtocol (\r
-                  HttpInstance->TcpChildHandle,\r
-                  &gEfiTcp4ProtocolGuid,\r
-                  (VOID **) &Interface,\r
-                  HttpInstance->Service->ImageHandle,\r
-                  HttpInstance->Service->ControllerHandle,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                  );\r
-                  \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
 \r
-  Status = gBS->OpenProtocol (\r
-                  HttpInstance->TcpChildHandle,\r
-                  &gEfiTcp4ProtocolGuid,\r
-                  (VOID **) &HttpInstance->Tcp4,\r
-                  HttpInstance->Service->ImageHandle,\r
-                  HttpInstance->Handle,\r
-                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-                  );\r
-  if (EFI_ERROR(Status)) {\r
-    goto ON_ERROR;\r
-  }\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Tcp6ChildHandle,\r
+                    &gEfiTcp6ProtocolGuid,\r
+                    (VOID **) &Interface,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Service->ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    );\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Tcp6ChildHandle,\r
+                    &gEfiTcp6ProtocolGuid,\r
+                    (VOID **) &HttpInstance->Tcp6,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+    \r
+    if (EFI_ERROR(Status)) {\r
+      goto ON_ERROR;\r
+    }      \r
+\r
+    Status = gBS->OpenProtocol (\r
+                    HttpInstance->Service->Tcp6ChildHandle,\r
+                    &gEfiTcp6ProtocolGuid,\r
+                    (VOID **) &Interface,\r
+                    HttpInstance->Service->ImageHandle,\r
+                    HttpInstance->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
 \r
+    if (EFI_ERROR(Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
+  \r
   HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);\r
   if (HttpInstance->Url == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_ERROR;\r
   }\r
 \r
-  NetMapInit (&HttpInstance->TxTokens);\r
-  NetMapInit (&HttpInstance->RxTokens);\r
-\r
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
   \r
-  if (HttpInstance->TcpChildHandle != NULL) {\r
+  if (HttpInstance->Tcp4ChildHandle != NULL) {\r
     gBS->CloseProtocol (\r
-           HttpInstance->TcpChildHandle,\r
+           HttpInstance->Tcp4ChildHandle,\r
            &gEfiTcp4ProtocolGuid,\r
            HttpInstance->Service->ImageHandle,\r
            HttpInstance->Service->ControllerHandle\r
            );\r
 \r
     gBS->CloseProtocol (\r
-           HttpInstance->TcpChildHandle,\r
+           HttpInstance->Tcp4ChildHandle,\r
            &gEfiTcp4ProtocolGuid,\r
            HttpInstance->Service->ImageHandle,\r
            HttpInstance->Handle\r
-           );\r
+           );    \r
     \r
     NetLibDestroyServiceChild (\r
       HttpInstance->Service->ControllerHandle,\r
       HttpInstance->Service->ImageHandle,\r
       &gEfiTcp4ServiceBindingProtocolGuid,\r
-      HttpInstance->TcpChildHandle\r
+      HttpInstance->Tcp4ChildHandle\r
       );\r
   }\r
+  \r
+  if (HttpInstance->Service->Tcp4ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Service->Tcp4ChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+  }\r
+  \r
+  if (HttpInstance->Tcp6ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Service->ControllerHandle\r
+           );\r
 \r
-  return Status;\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+    \r
+    NetLibDestroyServiceChild (\r
+      HttpInstance->Service->ControllerHandle,\r
+      HttpInstance->Service->ImageHandle,\r
+      &gEfiTcp6ServiceBindingProtocolGuid,\r
+      HttpInstance->Tcp6ChildHandle\r
+      );\r
+  }\r
+  \r
+  if (HttpInstance->Service->Tcp6ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Service->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
   \r
 }\r
 \r
@@ -520,7 +814,7 @@ HttpCleanProtocol (
 {\r
   HttpCloseConnection (HttpInstance);\r
   \r
-  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
+  HttpCloseTcpConnCloseEvent (HttpInstance);\r
 \r
   if (HttpInstance->CacheBody != NULL) {\r
     FreePool (HttpInstance->CacheBody);\r
@@ -537,25 +831,25 @@ HttpCleanProtocol (
     HttpFreeMsgParser (HttpInstance->MsgParser);\r
     HttpInstance->MsgParser = NULL;\r
   }\r
-\r
+  \r
   if (HttpInstance->Url != NULL) {\r
     FreePool (HttpInstance->Url);\r
     HttpInstance->Url = NULL;\r
   }\r
-\r
+  \r
   NetMapClean (&HttpInstance->TxTokens);\r
   NetMapClean (&HttpInstance->RxTokens);\r
 \r
-  if (HttpInstance->TcpChildHandle != NULL) {\r
+  if (HttpInstance->Tcp4ChildHandle != NULL) {\r
     gBS->CloseProtocol (\r
-           HttpInstance->TcpChildHandle,\r
+           HttpInstance->Tcp4ChildHandle,\r
            &gEfiTcp4ProtocolGuid,\r
            HttpInstance->Service->ImageHandle,\r
            HttpInstance->Service->ControllerHandle\r
            );\r
 \r
     gBS->CloseProtocol (\r
-           HttpInstance->TcpChildHandle,\r
+           HttpInstance->Tcp4ChildHandle,\r
            &gEfiTcp4ProtocolGuid,\r
            HttpInstance->Service->ImageHandle,\r
            HttpInstance->Handle\r
@@ -565,9 +859,51 @@ HttpCleanProtocol (
       HttpInstance->Service->ControllerHandle,\r
       HttpInstance->Service->ImageHandle,\r
       &gEfiTcp4ServiceBindingProtocolGuid,\r
-      HttpInstance->TcpChildHandle\r
+      HttpInstance->Tcp4ChildHandle\r
       );\r
   }\r
+\r
+  if (HttpInstance->Service->Tcp4ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Service->Tcp4ChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+  }  \r
+\r
+  if (HttpInstance->Tcp6ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Service->ControllerHandle\r
+           );\r
+\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+    \r
+    NetLibDestroyServiceChild (\r
+      HttpInstance->Service->ControllerHandle,\r
+      HttpInstance->Service->ImageHandle,\r
+      &gEfiTcp6ServiceBindingProtocolGuid,\r
+      HttpInstance->Tcp6ChildHandle\r
+      );\r
+  }\r
+  \r
+  if (HttpInstance->Service->Tcp6ChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->Service->Tcp6ChildHandle,\r
+           &gEfiTcp6ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+  }\r
+  \r
 }\r
 \r
 /**\r
@@ -586,27 +922,40 @@ HttpCreateConnection (
 {\r
   EFI_STATUS                    Status;\r
 \r
-  //\r
-  // Create events for variuos asynchronous operations.\r
-  //\r
-  HttpInstance->IsConnDone = FALSE;\r
-\r
   //\r
   // Connect to Http server\r
   //\r
-  HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY;\r
-  Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));\r
-    return Status;\r
-  }\r
-\r
-  while (!HttpInstance->IsConnDone) {\r
-    HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
-  }\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    HttpInstance->IsTcp4ConnDone = FALSE;\r
+    HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;\r
+    Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));\r
+      return Status;\r
+    }\r
+    \r
+    while (!HttpInstance->IsTcp4ConnDone) {\r
+      HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+    }\r
+    \r
+    Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;\r
+    \r
+  } else {\r
+    HttpInstance->IsTcp6ConnDone = FALSE;\r
+    HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;\r
+    Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));\r
+      return Status;\r
+    }\r
 \r
-  Status = HttpInstance->ConnToken.CompletionToken.Status;\r
+    while(!HttpInstance->IsTcp6ConnDone) {\r
+      HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+    }\r
 \r
+    Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;   \r
+  }\r
+  \r
   if (!EFI_ERROR (Status)) {\r
     HttpInstance->State = HTTP_STATE_TCP_CONNECTED;\r
   }\r
@@ -631,17 +980,32 @@ HttpCloseConnection (
   EFI_STATUS                Status;\r
 \r
   if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {\r
-    HttpInstance->CloseToken.AbortOnClose = TRUE;\r
-    HttpInstance->IsCloseDone             = FALSE;\r
-    \r
-    Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
 \r
-    while (!HttpInstance->IsCloseDone) {\r
-      HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+    if (HttpInstance->LocalAddressIsIPv6) {\r
+      HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;\r
+      HttpInstance->IsTcp6CloseDone             = FALSE;\r
+      Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      while (!HttpInstance->IsTcp6CloseDone) {\r
+        HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+      }\r
+      \r
+    } else {\r
+      HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;\r
+      HttpInstance->IsTcp4CloseDone             = FALSE;\r
+      Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      while (!HttpInstance->IsTcp4CloseDone) {\r
+        HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+      }\r
     }\r
+\r
   }\r
 \r
   HttpInstance->State = HTTP_STATE_TCP_CLOSED;\r
@@ -710,12 +1074,82 @@ HttpConfigureTcp4 (
     return Status;\r
   }\r
 \r
-  Status = HttpCreateTcp4ConnCloseEvent (HttpInstance);\r
+  Status = HttpCreateTcpConnCloseEvent (HttpInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpCreateTcpTxEvent (Wrap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HttpInstance->State = HTTP_STATE_TCP_CONFIGED;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Configure TCP6 protocol child.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The TCP6 protocol child is configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConfigureTcp6 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_TCP6_CONFIG_DATA     *Tcp6CfgData;\r
+  EFI_TCP6_ACCESS_POINT    *Tcp6Ap;\r
+  EFI_TCP6_OPTION          *Tcp6Option;\r
+  \r
+  ASSERT (HttpInstance != NULL);\r
+  \r
+  Tcp6CfgData = &HttpInstance->Tcp6CfgData;\r
+  ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));\r
+\r
+  Tcp6CfgData->TrafficClass  = 0;\r
+  Tcp6CfgData->HopLimit      = 255;\r
+  Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;\r
+  \r
+  Tcp6Ap  = &Tcp6CfgData->AccessPoint;\r
+  Tcp6Ap->ActiveFlag  = TRUE;\r
+  Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;\r
+  Tcp6Ap->RemotePort  = HttpInstance->RemotePort;\r
+  IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);\r
+  IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);\r
+\r
+  Tcp6Option = Tcp6CfgData->ControlOption;\r
+  Tcp6Option->ReceiveBufferSize  = HTTP_BUFFER_SIZE_DEAULT;\r
+  Tcp6Option->SendBufferSize     = HTTP_BUFFER_SIZE_DEAULT;\r
+  Tcp6Option->MaxSynBackLog      = HTTP_MAX_SYN_BACK_LOG;\r
+  Tcp6Option->ConnectionTimeout  = HTTP_CONNECTION_TIMEOUT;\r
+  Tcp6Option->DataRetries        = HTTP_DATA_RETRIES;\r
+  Tcp6Option->FinTimeout         = HTTP_FIN_TIMEOUT;\r
+  Tcp6Option->KeepAliveProbes    = HTTP_KEEP_ALIVE_PROBES;\r
+  Tcp6Option->KeepAliveTime      = HTTP_KEEP_ALIVE_TIME;\r
+  Tcp6Option->KeepAliveInterval  = HTTP_KEEP_ALIVE_INTERVAL;\r
+  Tcp6Option->EnableNagle        = TRUE;\r
+\r
+  Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));\r
+    return Status;\r
+  }\r
+  \r
+  Status = HttpCreateTcpConnCloseEvent (HttpInstance);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = HttpCreateTcp4TxEvent (Wrap);\r
+  Status = HttpCreateTcpTxEvent (Wrap);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -723,10 +1157,11 @@ HttpConfigureTcp4 (
   HttpInstance->State = HTTP_STATE_TCP_CONFIGED;\r
 \r
   return EFI_SUCCESS;\r
\r
 }\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, receover TCP4 connection.\r
+  Check existing TCP connection, if in error state, recover TCP4 connection.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -769,7 +1204,105 @@ HttpConnectTcp4 (
 }\r
 \r
 /**\r
-  Send the HTTP message through TCP4.\r
+  Check existing TCP connection, if in error state, recover TCP6 connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval EFI_NOT_READY          TCP6 protocol child is not created or configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConnectTcp6 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_TCP6_CONNECTION_STATE Tcp6State;\r
+\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = HttpInstance->Tcp6->GetModeData (\r
+                                 HttpInstance->Tcp6,\r
+                                 &Tcp6State,\r
+                                 NULL,\r
+                                 NULL,\r
+                                 NULL,\r
+                                 NULL\r
+                                 );\r
+  \r
+  if (EFI_ERROR(Status)){\r
+     DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));\r
+     return Status;\r
+  }\r
+\r
+  if (Tcp6State > Tcp6StateEstablished) {\r
+    HttpCloseConnection (HttpInstance);\r
+  }\r
+\r
+  return HttpCreateConnection (HttpInstance);\r
+}\r
+\r
+/**\r
+  Initialize TCP related data.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The initialization of TCP instance is done. \r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpInitTcp (\r
+  IN  HTTP_PROTOCOL    *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP  *Wrap\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    //\r
+    // Configure TCP instance.\r
+    //\r
+    Status = HttpConfigureTcp4 (HttpInstance, Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Connect TCP.\r
+    //\r
+    Status = HttpConnectTcp4 (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    //\r
+    // Configure TCP instance.\r
+    //\r
+    Status = HttpConfigureTcp6 (HttpInstance, Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Connect TCP.\r
+    //\r
+    Status = HttpConnectTcp6 (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+  \r
+}\r
+\r
+/**\r
+  Send the HTTP message through TCP4 or TCP6.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
@@ -781,7 +1314,7 @@ HttpConnectTcp4 (
 \r
 **/\r
 EFI_STATUS\r
-HttpTransmitTcp4 (\r
+HttpTransmitTcp (\r
   IN  HTTP_PROTOCOL    *HttpInstance,\r
   IN  HTTP_TOKEN_WRAP  *Wrap,\r
   IN  UINT8            *TxString,\r
@@ -789,23 +1322,44 @@ HttpTransmitTcp4 (
   )\r
 {\r
   EFI_STATUS                    Status;\r
-  EFI_TCP4_IO_TOKEN             *TxToken;\r
+  EFI_TCP4_IO_TOKEN             *Tx4Token;\r
   EFI_TCP4_PROTOCOL             *Tcp4;\r
+  EFI_TCP6_IO_TOKEN             *Tx6Token;\r
+  EFI_TCP6_PROTOCOL             *Tcp6;\r
   \r
-  Tcp4 = HttpInstance->Tcp4;\r
-  TxToken = &Wrap->TcpWrap.TxToken;\r
+  if (!HttpInstance->LocalAddressIsIPv6) {     \r
+    Tcp4 = HttpInstance->Tcp4;\r
+    Tx4Token = &Wrap->TcpWrap.Tx4Token;\r
+    \r
+    Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+    Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+    Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    Tx4Token->CompletionToken.Status = EFI_NOT_READY;  \r
+    \r
+    Wrap->TcpWrap.IsTxDone = FALSE;\r
+    Status  = Tcp4->Transmit (Tcp4, Tx4Token);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));\r
+      return Status;\r
+    }\r
 \r
-  TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
-  TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
-  TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
-  TxToken->CompletionToken.Status = EFI_NOT_READY;  \r
+  } else {\r
+    Tcp6 = HttpInstance->Tcp6;\r
+    Tx6Token = &Wrap->TcpWrap.Tx6Token;\r
 \r
-  Wrap->TcpWrap.IsTxDone = FALSE;\r
-  Status  = Tcp4->Transmit (Tcp4, TxToken);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));\r
-    return Status;\r
+    Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+    Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+    Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    Tx6Token->CompletionToken.Status = EFI_NOT_READY;\r
+\r
+    Wrap->TcpWrap.IsTxDone = FALSE;\r
+    Status = Tcp6->Transmit (Tcp6, Tx6Token);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));\r
+      return Status;\r
+    }\r
   }\r
+  \r
 \r
   return Status;\r
 }\r
@@ -913,7 +1467,7 @@ HttpMappingToStatusCode (
 \r
 /**\r
   Check whether the user's token or event has already\r
-  been enqueue on HTTP TxToken or RxToken list.\r
+  been enqueue on HTTP Tx or Rx Token list.\r
 \r
   @param[in]  Map                The container of either user's transmit or receive\r
                                  token.\r
@@ -947,9 +1501,9 @@ HttpTokenExist (
 }\r
 \r
 /**\r
-  Check whether the HTTP message associated with TxToken is already sent out.\r
+  Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.\r
 \r
-  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Map                The container of Tx4Token or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
   @param[in]  Context            The Token to check againist.\r
 \r
@@ -979,7 +1533,7 @@ HttpTcpNotReady (
 /**\r
   Transmit the HTTP mssage by processing the associated HTTP token.\r
 \r
-  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Map                The container of Tx4Token or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
   @param[in]  Context            The Token to check againist.\r
 \r
@@ -1032,7 +1586,7 @@ HttpTcpTransmit (
   //\r
   // Transmit the request message.\r
   //\r
-  Status = HttpTransmitTcp4 (\r
+  Status = HttpTransmitTcp (\r
              ValueInItem->HttpInstance,\r
              ValueInItem,\r
              (UINT8*) RequestStr,\r
@@ -1045,7 +1599,7 @@ HttpTcpTransmit (
 /**\r
   Receive the HTTP response by processing the associated HTTP token.\r
 \r
-  @param[in]  Map                The container of RxToken.\r
+  @param[in]  Map                The container of Rx4Token or Rx6Token.\r
   @param[in]  Item               Current item to check against.\r
   @param[in]  Context            The Token to check againist.\r
 \r
@@ -1068,6 +1622,319 @@ HttpTcpReceive (
   return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);\r
 }\r
 \r
+/**\r
+  Receive the HTTP header by processing the associated HTTP token.\r
+\r
+  @param[in]       HttpInstance     The HTTP instance private data.\r
+  @param[in, out]  SizeofHeaders    The HTTP header length.\r
+  @param[in, out]  BufferSize       The size of buffer to cacahe the header message.\r
+  \r
+  @retval EFI_SUCCESS               The HTTP header is received.                          \r
+  @retval Others                    Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTcpReceiveHeader (\r
+  IN  HTTP_PROTOCOL         *HttpInstance,\r
+  IN  OUT UINTN             *SizeofHeaders,\r
+  IN  OUT UINTN             *BufferSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_TCP4_IO_TOKEN             *Rx4Token;\r
+  EFI_TCP4_PROTOCOL             *Tcp4;\r
+  EFI_TCP6_IO_TOKEN             *Rx6Token;\r
+  EFI_TCP6_PROTOCOL             *Tcp6;\r
+  CHAR8                         **EndofHeader;\r
+  CHAR8                         **HttpHeaders;\r
+  CHAR8                         *Buffer;\r
+\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  EndofHeader = HttpInstance->EndofHeader;\r
+  HttpHeaders = HttpInstance->HttpHeaders;\r
+  Tcp4 = HttpInstance->Tcp4;\r
+  Tcp6 = HttpInstance->Tcp6;\r
+  Buffer      = NULL;\r
+  Rx4Token    = NULL;\r
+  Rx6Token    = NULL;\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    ASSERT (Tcp6 != NULL);\r
+  } else {\r
+    ASSERT (Tcp4 != NULL);\r
+  }\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Rx4Token = &HttpInstance->Rx4Token;\r
+    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+    if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+  \r
+    //\r
+    // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
+    //\r
+    while (*EndofHeader == NULL) {   \r
+      HttpInstance->IsRxDone = FALSE;\r
+      Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+      Status = Tcp4->Receive (Tcp4, Rx4Token);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+        return Status;\r
+      }\r
+      \r
+      while (!HttpInstance->IsRxDone) {\r
+       Tcp4->Poll (Tcp4);\r
+      }    \r
+  \r
+      Status = Rx4Token->CompletionToken.Status;\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+  \r
+      //\r
+      // Append the response string.\r
+      //\r
+      *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      Buffer      = AllocateZeroPool (*BufferSize);\r
+      if (Buffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
+  \r
+      if (*HttpHeaders != NULL) {\r
+        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        FreePool (*HttpHeaders);\r
+      }\r
+  \r
+      CopyMem (\r
+        Buffer + (*SizeofHeaders),\r
+        Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
+        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        );\r
+      *HttpHeaders    = Buffer;\r
+      *SizeofHeaders  = *BufferSize;\r
+  \r
+      //\r
+      // Check whether we received end of HTTP headers.\r
+      //\r
+      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); \r
+    }\r
+    FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    \r
+  } else {\r
+    Rx6Token = &HttpInstance->Rx6Token;\r
+    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+    if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+  \r
+    //\r
+    // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
+    //\r
+    while (*EndofHeader == NULL) {   \r
+      HttpInstance->IsRxDone = FALSE;\r
+      Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+      Status = Tcp6->Receive (Tcp6, Rx6Token);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+        return Status;\r
+      }\r
+      \r
+      while (!HttpInstance->IsRxDone) {\r
+       Tcp6->Poll (Tcp6);\r
+      }    \r
+  \r
+      Status = Rx6Token->CompletionToken.Status;\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+  \r
+      //\r
+      // Append the response string.\r
+      //\r
+      *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      Buffer      = AllocateZeroPool (*BufferSize);\r
+      if (Buffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
+  \r
+      if (*HttpHeaders != NULL) {\r
+        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        FreePool (*HttpHeaders);\r
+      }\r
+  \r
+      CopyMem (\r
+        Buffer + (*SizeofHeaders),\r
+        Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
+        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        );\r
+      *HttpHeaders     = Buffer;\r
+      *SizeofHeaders  = *BufferSize;\r
+  \r
+      //\r
+      // Check whether we received end of HTTP headers.\r
+      //\r
+      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);\r
+  \r
+    }\r
+    FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;    \r
+  }     \r
+\r
+  //\r
+  // Skip the CRLF after the HTTP headers.\r
+  //\r
+  *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);  \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Receive the HTTP body by processing the associated HTTP token.\r
+\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+  @param[in]  HttpMsg            The HTTP message data.\r
+\r
+  @retval EFI_SUCCESS            The HTTP body is received.                          \r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTcpReceiveBody (\r
+  IN  HTTP_TOKEN_WRAP       *Wrap,\r
+  IN  EFI_HTTP_MESSAGE      *HttpMsg\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  HTTP_PROTOCOL             *HttpInstance;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  EFI_TCP6_IO_TOKEN         *Rx6Token;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP4_IO_TOKEN         *Rx4Token;\r
+  \r
+  HttpInstance   = Wrap->HttpInstance;\r
+  Tcp4 = HttpInstance->Tcp4;\r
+  Tcp6 = HttpInstance->Tcp6;\r
+  Rx4Token       = NULL;\r
+  Rx6Token       = NULL;\r
+\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    ASSERT (Tcp6 != NULL);\r
+  } else {\r
+    ASSERT (Tcp4 != NULL);\r
+  }\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    Rx6Token = &Wrap->TcpWrap.Rx6Token;\r
+    Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;\r
+    Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;\r
+    Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;\r
+    Rx6Token->CompletionToken.Status = EFI_NOT_READY;\r
+\r
+    Status = Tcp6->Receive (Tcp6, Rx6Token);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+      return Status;\r
+    }\r
+      \r
+  } else {\r
+    Rx4Token = &Wrap->TcpWrap.Rx4Token;\r
+    Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;\r
+    Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;\r
+    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;\r
+    \r
+    Rx4Token->CompletionToken.Status = EFI_NOT_READY;\r
+    Status = Tcp4->Receive (Tcp4, Rx4Token);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Clean up Tcp Tokens while the Tcp transmission error occurs.\r
+\r
+  @param[in]  Wrap               Pointer to HTTP token's wrap data.\r
+  \r
+**/\r
+VOID\r
+HttpTcpTokenCleanup (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  )\r
+{ \r
+  HTTP_PROTOCOL            *HttpInstance;\r
+  EFI_TCP4_IO_TOKEN        *Rx4Token;\r
+  EFI_TCP6_IO_TOKEN        *Rx6Token;\r
+\r
+  HttpInstance   = Wrap->HttpInstance;\r
+  Rx4Token       = NULL;\r
+  Rx6Token       = NULL;\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    if (Wrap != NULL) {\r
+      if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+        gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
+      }\r
+\r
+      Rx6Token = &Wrap->TcpWrap.Rx6Token;\r
+      if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+        FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+        Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      }\r
+      FreePool (Wrap); \r
+    }\r
+\r
+    if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);\r
+      HttpInstance->Rx6Token.CompletionToken.Event = NULL;\r
+    }\r
+\r
+    Rx6Token = &HttpInstance->Rx6Token;\r
+    if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    }\r
+    \r
+  } else {\r
+    if (Wrap != NULL) {\r
+      if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+        gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+      }\r
+      Rx4Token = &Wrap->TcpWrap.Rx4Token;\r
+      if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+        FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+        Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      }\r
+      FreePool (Wrap);\r
+    }\r
+    \r
+    if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);\r
+      HttpInstance->Rx4Token.CompletionToken.Event = NULL;\r
+    }\r
+    \r
+    Rx4Token = &HttpInstance->Rx4Token;\r
+    if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    }\r
+  }\r
+\r
+}\r
+\r
 /**\r
   Generate HTTP request string.\r
 \r
index c37b80c8ec745d62e5f2a34ba2c227757ed0fcbe..a15e0a87be53bd1678187cf5edbf2dec789363b9 100644 (file)
@@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
   HTTP_SERVICE_SIGNATURE \\r
   )\r
 \r
+\r
 //\r
 // The state of HTTP protocol. It starts from UNCONFIGED.\r
 //\r
@@ -58,18 +59,23 @@ typedef struct _HTTP_SERVICE {
   EFI_SERVICE_BINDING_PROTOCOL  ServiceBinding;\r
   EFI_HANDLE                    ImageHandle;\r
   EFI_HANDLE                    ControllerHandle;\r
+  EFI_HANDLE                    Tcp4ChildHandle;\r
+  EFI_HANDLE                    Tcp6ChildHandle;\r
   LIST_ENTRY                    ChildrenList;\r
   UINTN                         ChildrenNumber;\r
-  EFI_HANDLE                    TcpChildHandle;\r
   INTN                          State;\r
 } HTTP_SERVICE;\r
 \r
 typedef struct {\r
-  EFI_TCP4_IO_TOKEN             TxToken;\r
-  EFI_TCP4_TRANSMIT_DATA        TxData;\r
+  EFI_TCP4_IO_TOKEN             Tx4Token;\r
+  EFI_TCP4_TRANSMIT_DATA        Tx4Data;\r
+  EFI_TCP6_IO_TOKEN             Tx6Token;\r
+  EFI_TCP6_TRANSMIT_DATA        Tx6Data;\r
+  EFI_TCP4_IO_TOKEN             Rx4Token;\r
+  EFI_TCP4_RECEIVE_DATA         Rx4Data;\r
+  EFI_TCP6_IO_TOKEN             Rx6Token;\r
+  EFI_TCP6_RECEIVE_DATA         Rx6Data;\r
   BOOLEAN                       IsTxDone;\r
-  EFI_TCP4_IO_TOKEN             RxToken;\r
-  EFI_TCP4_RECEIVE_DATA         RxData;\r
   BOOLEAN                       IsRxDone;\r
   UINTN                         BodyLen;\r
   EFI_HTTP_METHOD               Method;\r
@@ -84,26 +90,43 @@ typedef struct _HTTP_PROTOCOL {
   BOOLEAN                       InDestroy;\r
   INTN                          State;\r
 \r
-  EFI_HANDLE                    TcpChildHandle;\r
+  EFI_HANDLE                    Tcp4ChildHandle;\r
   EFI_TCP4_PROTOCOL             *Tcp4;\r
   EFI_TCP4_CONFIG_DATA          Tcp4CfgData;\r
   EFI_TCP4_OPTION               Tcp4Option;\r
 \r
-  EFI_TCP4_CONNECTION_TOKEN     ConnToken;\r
-  BOOLEAN                       IsConnDone;\r
-  EFI_TCP4_CLOSE_TOKEN          CloseToken;\r
-  BOOLEAN                       IsCloseDone;\r
-\r
+  EFI_TCP4_CONNECTION_TOKEN     Tcp4ConnToken;\r
+  BOOLEAN                       IsTcp4ConnDone;\r
+  EFI_TCP4_CLOSE_TOKEN          Tcp4CloseToken;\r
+  BOOLEAN                       IsTcp4CloseDone;\r
   CHAR8                         *RemoteHost;\r
   UINT16                        RemotePort;\r
   EFI_IPv4_ADDRESS              RemoteAddr;\r
+  \r
+  EFI_HANDLE                    Tcp6ChildHandle;\r
+  EFI_TCP6_PROTOCOL             *Tcp6;\r
+  EFI_TCP6_CONFIG_DATA          Tcp6CfgData;\r
+  EFI_TCP6_OPTION               Tcp6Option;\r
+  \r
+  EFI_TCP6_CONNECTION_TOKEN     Tcp6ConnToken;\r
+  BOOLEAN                       IsTcp6ConnDone;\r
+  EFI_TCP6_CLOSE_TOKEN          Tcp6CloseToken;\r
+  BOOLEAN                       IsTcp6CloseDone;\r
+  EFI_IPv6_ADDRESS              RemoteIpv6Addr;\r
+\r
+\r
+  \r
   //\r
-  // RxToken used for receiving HTTP header.\r
+  // Rx4Token or Rx6Token used for receiving HTTP header.\r
   //\r
-  EFI_TCP4_IO_TOKEN             RxToken;\r
-  EFI_TCP4_RECEIVE_DATA         RxData;\r
+  EFI_TCP4_IO_TOKEN             Rx4Token;\r
+  EFI_TCP4_RECEIVE_DATA         Rx4Data;\r
+  EFI_TCP6_IO_TOKEN             Rx6Token;\r
+  EFI_TCP6_RECEIVE_DATA         Rx6Data;\r
   BOOLEAN                       IsRxDone;\r
 \r
+  CHAR8                         **EndofHeader;\r
+  CHAR8                         **HttpHeaders;\r
   CHAR8                         *CacheBody;\r
   CHAR8                         *NextMsg;\r
   UINTN                         CacheLen;\r
@@ -119,6 +142,7 @@ typedef struct _HTTP_PROTOCOL {
   BOOLEAN                       LocalAddressIsIPv6;\r
 \r
   EFI_HTTPv4_ACCESS_POINT       IPv4Node;\r
+  EFI_HTTPv6_ACCESS_POINT       Ipv6Node;\r
 \r
   NET_MAP                       TxTokens;\r
   NET_MAP                       RxTokens;\r
@@ -158,7 +182,7 @@ HttpCommonNotify (
   );\r
 \r
 /**\r
-  Create events for the TCP4 connection token and TCP4 close token.\r
+  Create events for the TCP connection token and TCP close token.\r
 \r
   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
 \r
@@ -167,23 +191,23 @@ HttpCommonNotify (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4ConnCloseEvent (\r
+HttpCreateTcpConnCloseEvent (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   );\r
 \r
 /**\r
-  Close events in the TCP4 connection token and TCP4 close token.\r
+  Close events in the TCP connection token and TCP close token.\r
 \r
   @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.\r
 \r
 **/\r
 VOID\r
-HttpCloseTcp4ConnCloseEvent (\r
+HttpCloseTcpConnCloseEvent (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   );\r
 \r
 /**\r
-  Create event for the TCP4 transmit token.\r
+  Create event for the TCP transmit token.\r
 \r
   @param[in]  Wrap               Point to HTTP token's wrap data.\r
 \r
@@ -192,12 +216,12 @@ HttpCloseTcp4ConnCloseEvent (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4TxEvent (\r
+HttpCreateTcpTxEvent (\r
   IN  HTTP_TOKEN_WRAP      *Wrap\r
   );\r
 \r
 /**\r
-  Create event for the TCP4 receive token which is used to receive HTTP header.\r
+  Create event for the TCP receive token which is used to receive HTTP header.\r
 \r
   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
 \r
@@ -206,12 +230,12 @@ HttpCreateTcp4TxEvent (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4RxEventForHeader (\r
+HttpCreateTcpRxEventForHeader (\r
   IN  HTTP_PROTOCOL        *HttpInstance\r
   );\r
 \r
 /**\r
-  Create event for the TCP4 receive token which is used to receive HTTP body.\r
+  Create event for the TCP receive token which is used to receive HTTP body.\r
 \r
   @param[in]  Wrap               Point to HTTP token's wrap data.\r
 \r
@@ -220,15 +244,26 @@ HttpCreateTcp4RxEventForHeader (
 \r
 **/\r
 EFI_STATUS\r
-HttpCreateTcp4RxEvent (\r
+HttpCreateTcpRxEvent (\r
   IN  HTTP_TOKEN_WRAP      *Wrap \r
   );\r
 \r
+/**\r
+  Close Events for Tcp Receive Tokens for HTTP body and HTTP header.\r
+\r
+  @param[in]  Wrap               Pointer to HTTP token's wrap data.\r
+  \r
+**/\r
+VOID\r
+HttpCloseTcpRxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  );\r
+\r
 /**\r
   Intiialize the HTTP_PROTOCOL structure to the unconfigured state.\r
 \r
-  @param[in]       HttpSb               The HTTP service private instance.\r
   @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]       IpVersion            Indicate us TCP4 protocol or TCP6 protocol.\r
 \r
   @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.                                          \r
   @retval Others            Other error as indicated.\r
@@ -236,8 +271,8 @@ HttpCreateTcp4RxEvent (
 **/\r
 EFI_STATUS\r
 HttpInitProtocol (\r
-  IN     HTTP_SERVICE            *HttpSb,\r
-  IN OUT HTTP_PROTOCOL           *HttpInstance\r
+  IN OUT HTTP_PROTOCOL           *HttpInstance,\r
+  IN     BOOLEAN                 IpVersion\r
   );\r
 \r
 /**\r
@@ -295,6 +330,22 @@ HttpConfigureTcp4 (
   IN  HTTP_TOKEN_WRAP      *Wrap\r
   );\r
 \r
+/**\r
+  Configure TCP6 protocol child.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The TCP6 protocol child is configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConfigureTcp6 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  );\r
+\r
 /**\r
   Check existing TCP connection, if in error state, receover TCP4 connection.\r
 \r
@@ -311,7 +362,22 @@ HttpConnectTcp4 (
   );\r
 \r
 /**\r
-  Send the HTTP message through TCP4.\r
+  Check existing TCP connection, if in error state, recover TCP6 connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval EFI_NOT_READY          TCP6 protocol child is not created or configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConnectTcp6 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Send the HTTP message through TCP4 or TCP6.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
@@ -323,7 +389,7 @@ HttpConnectTcp4 (
 \r
 **/\r
 EFI_STATUS\r
-HttpTransmitTcp4 (\r
+HttpTransmitTcp (\r
   IN  HTTP_PROTOCOL    *HttpInstance,\r
   IN  HTTP_TOKEN_WRAP  *Wrap,\r
   IN  UINT8            *TxString,\r
@@ -346,7 +412,7 @@ HttpMappingToStatusCode (
 \r
 /**\r
   Check whether the user's token or event has already\r
-  been enqueue on HTTP TxToken or RxToken list.\r
+  been enqueue on HTTP Tx or Rx Token list.\r
 \r
   @param[in]  Map                The container of either user's transmit or receive\r
                                  token.\r
@@ -367,7 +433,7 @@ HttpTokenExist (
   );\r
 \r
 /**\r
-  Check whether the HTTP message associated with TxToken is already sent out.\r
+  Check whether the HTTP message associated with TxToken or Tx6Token is already sent out.\r
 \r
   @param[in]  Map                The container of TxToken.\r
   @param[in]  Item               Current item to check against.\r
@@ -385,10 +451,26 @@ HttpTcpNotReady (
   IN VOID                   *Context\r
   );\r
 \r
+/**\r
+  Initialize TCP related data.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The initialization of TCP instance is done. \r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpInitTcp (\r
+  IN  HTTP_PROTOCOL    *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP  *Wrap\r
+  );\r
+\r
 /**\r
   Transmit the HTTP mssage by processing the associated HTTP token.\r
 \r
-  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Map                The container of TxToken or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
   @param[in]  Context            The Token to check againist.\r
 \r
@@ -408,7 +490,7 @@ HttpTcpTransmit (
 /**\r
   Receive the HTTP response by processing the associated HTTP token.\r
 \r
-  @param[in]  Map                The container of RxToken.\r
+  @param[in]  Map                The container of Rx4Token or Rx6Token.\r
   @param[in]  Item               Current item to check against.\r
   @param[in]  Context            The Token to check againist.\r
 \r
@@ -425,6 +507,51 @@ HttpTcpReceive (
   IN VOID                   *Context\r
   );\r
 \r
+/**\r
+  Receive the HTTP header by processing the associated HTTP token.\r
+\r
+  @param[in]       HttpInstance    The HTTP instance private data.\r
+  @param[in, out]  SizeofHeaders   The HTTP header length.\r
+  @param[in, out]  BufferSize      The size of buffer to cacahe the header message.\r
+\r
+  @retval EFI_SUCCESS              The HTTP header is received.                          \r
+  @retval Others                   Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTcpReceiveHeader (\r
+  IN  HTTP_PROTOCOL         *HttpInstance,\r
+  IN  OUT UINTN             *SizeofHeaders,\r
+  IN  OUT UINTN             *BufferSize\r
+  );\r
+\r
+/**\r
+  Receive the HTTP body by processing the associated HTTP token.\r
+\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+  @param[in]  HttpMsg            The HTTP message data.\r
+\r
+  @retval EFI_SUCCESS            The HTTP body is received.                          \r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTcpReceiveBody (\r
+  IN  HTTP_TOKEN_WRAP       *Wrap,\r
+  IN  EFI_HTTP_MESSAGE      *HttpMsg\r
+  );\r
+\r
+/**\r
+  Clean up Tcp Tokens while the Tcp transmission error occurs.\r
+\r
+  @param[in]  Wrap               Pointer to HTTP token's wrap data.\r
+  \r
+**/\r
+VOID\r
+HttpTcpTokenCleanup (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  );\r
+\r
 /**\r
   Generate HTTP request string.\r
 \r