]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpBootDxe/HttpBootClient.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootClient.c
index f0817e92e21e38b3d7ef4ccf606947ce2efbf605..40f64fcb6bf82ccec2de6d41ab22f75b4f890b7b 100644 (file)
@@ -1,42 +1,39 @@
 /** @file\r
   Implementation of the boot file download function.\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
+Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "HttpBootDxe.h"\r
 \r
 /**\r
-  Update the IP and URL device path node to include the boot resource information.\r
+  Update the device path node to include the boot resource information.\r
 \r
   @param[in]    Private            The pointer to the driver's private data.\r
 \r
   @retval EFI_SUCCESS              Device patch successfully updated.\r
   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
   @retval Others                   Unexpected error happened.\r
-  \r
+\r
 **/\r
 EFI_STATUS\r
 HttpBootUpdateDevicePath (\r
-  IN   HTTP_BOOT_PRIVATE_DATA   *Private\r
+  IN   HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
-  EFI_DEV_PATH               *Node;\r
-  EFI_DEVICE_PATH_PROTOCOL   *TmpDevicePath;\r
-  EFI_DEVICE_PATH_PROTOCOL   *NewDevicePath;\r
-  UINTN                      Length;\r
-  EFI_STATUS                 Status;\r
+  EFI_DEV_PATH              *Node;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TmpIpDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TmpDnsDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
+  UINTN                     Length;\r
+  EFI_STATUS                Status;\r
+\r
+  TmpIpDevicePath  = NULL;\r
+  TmpDnsDevicePath = NULL;\r
 \r
-  TmpDevicePath = NULL;\r
-  \r
   //\r
   // Update the IP node with DHCP assigned information.\r
   //\r
@@ -45,6 +42,7 @@ HttpBootUpdateDevicePath (
     if (Node == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
+\r
     Node->Ipv4.Header.Type    = MESSAGING_DEVICE_PATH;\r
     Node->Ipv4.Header.SubType = MSG_IPv4_DP;\r
     SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));\r
@@ -59,41 +57,83 @@ HttpBootUpdateDevicePath (
     if (Node == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
-    Node->Ipv6.Header.Type     = MESSAGING_DEVICE_PATH;\r
-    Node->Ipv6.Header.SubType  = MSG_IPv6_DP;\r
+\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.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
+\r
+  TmpIpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);\r
   FreePool (Node);\r
-  if (TmpDevicePath == NULL) {\r
+  if (TmpIpDevicePath == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  //\r
+  // Update the DNS node with DNS server IP list if existed.\r
+  //\r
+  if (Private->DnsServerIp != NULL) {\r
+    Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6) + Private->DnsServerCount * sizeof (EFI_IP_ADDRESS);\r
+    Node   = AllocatePool (Length);\r
+    if (Node == NULL) {\r
+      FreePool (TmpIpDevicePath);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Node->DevPath.Type    = MESSAGING_DEVICE_PATH;\r
+    Node->DevPath.SubType = MSG_DNS_DP;\r
+    SetDevicePathNodeLength (Node, Length);\r
+    Node->Dns.IsIPv6 = Private->UsingIpv6 ? 0x01 : 0x00;\r
+    CopyMem ((UINT8 *)Node + sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6), Private->DnsServerIp, Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));\r
+\r
+    TmpDnsDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);\r
+    FreePool (Node);\r
+    FreePool (TmpIpDevicePath);\r
+    TmpIpDevicePath = NULL;\r
+    if (TmpDnsDevicePath == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
   //\r
   // Update the URI node with the boot file URI.\r
   //\r
   Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (Private->BootFileUri);\r
-  Node = AllocatePool (Length);\r
+  Node   = AllocatePool (Length);\r
   if (Node == NULL) {\r
-    FreePool (TmpDevicePath);\r
+    if (TmpIpDevicePath != NULL) {\r
+      FreePool (TmpIpDevicePath);\r
+    }\r
+\r
+    if (TmpDnsDevicePath != NULL) {\r
+      FreePool (TmpDnsDevicePath);\r
+    }\r
+\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
   Node->DevPath.Type    = MESSAGING_DEVICE_PATH;\r
   Node->DevPath.SubType = MSG_URI_DP;\r
   SetDevicePathNodeLength (Node, Length);\r
-  CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), Private->BootFileUri, AsciiStrSize (Private->BootFileUri));\r
-  \r
-  NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+  CopyMem ((UINT8 *)Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), Private->BootFileUri, AsciiStrSize (Private->BootFileUri));\r
+\r
+  if (TmpDnsDevicePath != NULL) {\r
+    NewDevicePath = AppendDevicePathNode (TmpDnsDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);\r
+    FreePool (TmpDnsDevicePath);\r
+  } else {\r
+    ASSERT (TmpIpDevicePath != NULL);\r
+    NewDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);\r
+    FreePool (TmpIpDevicePath);\r
+  }\r
+\r
   FreePool (Node);\r
-  FreePool (TmpDevicePath);\r
   if (NewDevicePath == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -111,7 +151,7 @@ HttpBootUpdateDevicePath (
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-    \r
+\r
     FreePool (Private->Ip4Nic->DevicePath);\r
     Private->Ip4Nic->DevicePath = NewDevicePath;\r
   } else {\r
@@ -127,10 +167,11 @@ HttpBootUpdateDevicePath (
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+\r
     FreePool (Private->Ip6Nic->DevicePath);\r
     Private->Ip6Nic->DevicePath = NewDevicePath;\r
   }\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -145,21 +186,24 @@ HttpBootUpdateDevicePath (
 **/\r
 EFI_STATUS\r
 HttpBootDhcp4ExtractUriInfo (\r
-  IN     HTTP_BOOT_PRIVATE_DATA   *Private\r
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
-  HTTP_BOOT_DHCP4_PACKET_CACHE    *SelectOffer;\r
-  HTTP_BOOT_DHCP4_PACKET_CACHE    *HttpOffer;\r
-  UINT32                          SelectIndex;\r
-  UINT32                          ProxyIndex;\r
-  EFI_DHCP4_PACKET_OPTION         *Option;\r
-  EFI_STATUS                      Status;\r
+  HTTP_BOOT_DHCP4_PACKET_CACHE  *SelectOffer;\r
+  HTTP_BOOT_DHCP4_PACKET_CACHE  *HttpOffer;\r
+  UINT32                        SelectIndex;\r
+  UINT32                        ProxyIndex;\r
+  UINT32                        DnsServerIndex;\r
+  EFI_DHCP4_PACKET_OPTION       *Option;\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
+  DnsServerIndex = 0;\r
+\r
   Status = EFI_SUCCESS;\r
 \r
   //\r
@@ -167,26 +211,78 @@ HttpBootDhcp4ExtractUriInfo (
   // HttpOffer contains the boot file URL.\r
   //\r
   SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp4;\r
-  if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {\r
-    HttpOffer = SelectOffer;\r
+  if (Private->FilePathUri == NULL) {\r
+    //\r
+    // In Corporate environment, we need a HttpOffer.\r
+    //\r
+    if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||\r
+        (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||\r
+        (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns))\r
+    {\r
+      HttpOffer = SelectOffer;\r
+    } else {\r
+      ASSERT (Private->SelectProxyType != HttpOfferTypeMax);\r
+      ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
+      HttpOffer  = &Private->OfferBuffer[ProxyIndex].Dhcp4;\r
+    }\r
+\r
+    Private->BootFileUriParser = HttpOffer->UriParser;\r
+    Private->BootFileUri       = (CHAR8 *)HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data;\r
   } else {\r
-    ASSERT (Private->SelectProxyType != HttpOfferTypeMax);\r
-    ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
-    HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp4;\r
+    //\r
+    // In Home environment the BootFileUri comes from the FilePath.\r
+    //\r
+    Private->BootFileUriParser = Private->FilePathUriParser;\r
+    Private->BootFileUri       = Private->FilePathUri;\r
   }\r
 \r
   //\r
-  // Configure the default DNS server if server assigned.\r
+  // Check the URI scheme.\r
   //\r
-  if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {\r
+  Status = HttpBootCheckUriScheme (Private->BootFileUri);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "HttpBootDhcp4ExtractUriInfo: %r.\n", Status));\r
+    if (Status == EFI_INVALID_PARAMETER) {\r
+      AsciiPrint ("\n  Error: Invalid URI address.\n");\r
+    } else if (Status == EFI_ACCESS_DENIED) {\r
+      AsciiPrint ("\n  Error: Access forbidden, only HTTPS connection is allowed.\n");\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||\r
+      (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||\r
+      (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns))\r
+  {\r
     Option = SelectOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];\r
     ASSERT (Option != NULL);\r
+\r
+    //\r
+    // Record the Dns Server address list.\r
+    //\r
+    Private->DnsServerCount = (Option->Length) / sizeof (EFI_IPv4_ADDRESS);\r
+\r
+    Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));\r
+    if (Private->DnsServerIp == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {\r
+      CopyMem (&(Private->DnsServerIp[DnsServerIndex].v4), &(((EFI_IPv4_ADDRESS *)Option->Data)[DnsServerIndex]), sizeof (EFI_IPv4_ADDRESS));\r
+    }\r
+\r
+    //\r
+    // Configure the default DNS server if server assigned.\r
+    //\r
     Status = HttpBootRegisterIp4Dns (\r
                Private,\r
                Option->Length,\r
                Option->Data\r
                );\r
     if (EFI_ERROR (Status)) {\r
+      FreePool (Private->DnsServerIp);\r
+      Private->DnsServerIp = NULL;\r
       return Status;\r
     }\r
   }\r
@@ -195,30 +291,26 @@ HttpBootDhcp4ExtractUriInfo (
   // Extract the port from URL, and use default HTTP port 80 if not provided.\r
   //\r
   Status = HttpUrlGetPort (\r
-             (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
-             HttpOffer->UriParser,\r
+             Private->BootFileUri,\r
+             Private->BootFileUriParser,\r
              &Private->Port\r
              );\r
-  if (EFI_ERROR (Status) || Private->Port == 0) {\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_DHCP4_TAG_INDEX_BOOTFILE]->Data;\r
 \r
-  \r
   //\r
   // All boot informations are valid here.\r
   //\r
-  AsciiPrint ("\n  URI: %a", Private->BootFileUri);\r
 \r
   //\r
-  // Update the device path to include the IP and boot URI information.\r
+  // Update the device path to include the boot resource information.\r
   //\r
   Status = HttpBootUpdateDevicePath (Private);\r
+  if (EFI_ERROR (Status) && (Private->DnsServerIp != NULL)) {\r
+    FreePool (Private->DnsServerIp);\r
+    Private->DnsServerIp = NULL;\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -234,24 +326,28 @@ HttpBootDhcp4ExtractUriInfo (
 **/\r
 EFI_STATUS\r
 HttpBootDhcp6ExtractUriInfo (\r
-  IN     HTTP_BOOT_PRIVATE_DATA   *Private\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
+  HTTP_BOOT_DHCP6_PACKET_CACHE  *SelectOffer;\r
+  HTTP_BOOT_DHCP6_PACKET_CACHE  *HttpOffer;\r
+  UINT32                        SelectIndex;\r
+  UINT32                        ProxyIndex;\r
+  UINT32                        DnsServerIndex;\r
+  EFI_DHCP6_PACKET_OPTION       *Option;\r
+  EFI_IPv6_ADDRESS              IpAddr;\r
+  CHAR8                         *HostName;\r
+  UINTN                         HostNameSize;\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
+  DnsServerIndex = 0;\r
+\r
   Status   = EFI_SUCCESS;\r
   HostName = NULL;\r
   //\r
@@ -259,12 +355,44 @@ HttpBootDhcp6ExtractUriInfo (
   // 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
+  if (Private->FilePathUri == NULL) {\r
+    //\r
+    // In Corporate environment, we need a HttpOffer.\r
+    //\r
+    if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||\r
+        (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||\r
+        (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns))\r
+    {\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
+    Private->BootFileUriParser = HttpOffer->UriParser;\r
+    Private->BootFileUri       = (CHAR8 *)HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data;\r
   } else {\r
-    ASSERT (Private->SelectProxyType != HttpOfferTypeMax);\r
-    ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
-    HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;\r
+    //\r
+    // In Home environment the BootFileUri comes from the FilePath.\r
+    //\r
+    Private->BootFileUriParser = Private->FilePathUriParser;\r
+    Private->BootFileUri       = Private->FilePathUri;\r
+  }\r
+\r
+  //\r
+  // Check the URI scheme.\r
+  //\r
+  Status = HttpBootCheckUriScheme (Private->BootFileUri);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "HttpBootDhcp6ExtractUriInfo: %r.\n", Status));\r
+    if (Status == EFI_INVALID_PARAMETER) {\r
+      AsciiPrint ("\n  Error: Invalid URI address.\n");\r
+    } else if (Status == EFI_ACCESS_DENIED) {\r
+      AsciiPrint ("\n  Error: Access forbidden, only HTTPS connection is allowed.\n");\r
+    }\r
+\r
+    return Status;\r
   }\r
 \r
   //\r
@@ -274,108 +402,130 @@ HttpBootDhcp6ExtractUriInfo (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
-  // Configure the default DNS server if server assigned.\r
+  // Register the IPv6 gateway address to the network device.\r
   //\r
-  if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {\r
+  Status = HttpBootSetIp6Gateway (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||\r
+      (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||\r
+      (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns))\r
+  {\r
     Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];\r
     ASSERT (Option != NULL);\r
+\r
+    //\r
+    // Record the Dns Server address list.\r
+    //\r
+    Private->DnsServerCount = HTONS (Option->OpLen) / sizeof (EFI_IPv6_ADDRESS);\r
+\r
+    Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));\r
+    if (Private->DnsServerIp == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {\r
+      CopyMem (&(Private->DnsServerIp[DnsServerIndex].v6), &(((EFI_IPv6_ADDRESS *)Option->Data)[DnsServerIndex]), sizeof (EFI_IPv6_ADDRESS));\r
+    }\r
+\r
+    //\r
+    // Configure the default DNS server if server assigned.\r
+    //\r
     Status = HttpBootSetIp6Dns (\r
                Private,\r
                HTONS (Option->OpLen),\r
                Option->Data\r
                );\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto Error;\r
     }\r
   }\r
-  \r
+\r
   //\r
-  // Extract the HTTP server Ip frome URL. This is used to Check route table \r
+  // Extract the HTTP server Ip from 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
+             Private->BootFileUri,\r
+             Private->BootFileUriParser,\r
              &IpAddr\r
              );\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
+               Private->BootFileUri,\r
+               Private->BootFileUriParser,\r
                &HostName\r
                );\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto Error;\r
     }\r
-    \r
-    HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
+\r
+    HostNameSize = AsciiStrSize (HostName);\r
+    HostNameStr  = AllocateZeroPool (HostNameSize * sizeof (CHAR16));\r
     if (HostNameStr == NULL) {\r
       Status = EFI_OUT_OF_RESOURCES;\r
       goto Error;\r
     }\r
-    \r
-    AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+\r
+    AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);\r
+\r
+    if (HostName != NULL) {\r
+      FreePool (HostName);\r
+    }\r
+\r
     Status = HttpBootDns (Private, HostNameStr, &IpAddr);\r
     FreePool (HostNameStr);\r
     if (EFI_ERROR (Status)) {\r
+      AsciiPrint ("\n  Error: Could not retrieve the host address from DNS server.\n");\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
+\r
+  CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS));\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->BootFileUri,\r
+             Private->BootFileUriParser,\r
              &Private->Port\r
              );\r
-  if (EFI_ERROR (Status) || Private->Port == 0) {\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
   //\r
-  // Update the device path to include the IP and boot URI information.\r
+  // Update the device path to include the boot resource information.\r
   //\r
   Status = HttpBootUpdateDevicePath (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  return Status;\r
 \r
 Error:\r
-  \r
-  if (HostName != NULL) {\r
-    FreePool (HostName);\r
+  if (Private->DnsServerIp != NULL) {\r
+    FreePool (Private->DnsServerIp);\r
+    Private->DnsServerIp = NULL;\r
   }\r
-    \r
+\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
   Discover all the boot information for boot file.\r
 \r
@@ -387,11 +537,11 @@ Error:
 **/\r
 EFI_STATUS\r
 HttpBootDiscoverBootInfo (\r
-  IN OUT HTTP_BOOT_PRIVATE_DATA   *Private\r
+  IN OUT HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
-  \r
+  EFI_STATUS  Status;\r
+\r
   //\r
   // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and\r
   // other Http boot information.\r
@@ -410,6 +560,42 @@ HttpBootDiscoverBootInfo (
   return Status;\r
 }\r
 \r
+/**\r
+  HttpIo Callback function which will be invoked when specified HTTP_IO_CALLBACK_EVENT happened.\r
+\r
+  @param[in]    EventType      Indicate the Event type that occurs in the current callback.\r
+  @param[in]    Message        HTTP message which will be send to, or just received from HTTP server.\r
+  @param[in]    Context        The Callback Context pointer.\r
+\r
+  @retval EFI_SUCCESS          Tells the HttpIo to continue the HTTP process.\r
+  @retval Others               Tells the HttpIo to abort the current HTTP process.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootHttpIoCallback (\r
+  IN  HTTP_IO_CALLBACK_EVENT  EventType,\r
+  IN  EFI_HTTP_MESSAGE        *Message,\r
+  IN  VOID                    *Context\r
+  )\r
+{\r
+  HTTP_BOOT_PRIVATE_DATA  *Private;\r
+  EFI_STATUS              Status;\r
+\r
+  Private = (HTTP_BOOT_PRIVATE_DATA *)Context;\r
+  if (Private->HttpBootCallback != NULL) {\r
+    Status = Private->HttpBootCallback->Callback (\r
+                                          Private->HttpBootCallback,\r
+                                          EventType == HttpIoRequest ? HttpBootHttpRequest : HttpBootHttpResponse,\r
+                                          EventType == HttpIoRequest ? FALSE : TRUE,\r
+                                          sizeof (EFI_HTTP_MESSAGE),\r
+                                          (VOID *)Message\r
+                                          );\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Create a HttpIo instance for the file download.\r
 \r
@@ -421,31 +607,42 @@ HttpBootDiscoverBootInfo (
 **/\r
 EFI_STATUS\r
 HttpBootCreateHttpIo (\r
-  IN     HTTP_BOOT_PRIVATE_DATA       *Private\r
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
-  HTTP_IO_CONFIG_DATA          ConfigData;\r
-  EFI_STATUS                   Status;\r
+  HTTP_IO_CONFIG_DATA  ConfigData;\r
+  EFI_STATUS           Status;\r
+  EFI_HANDLE           ImageHandle;\r
+  UINT32               TimeoutValue;\r
 \r
   ASSERT (Private != NULL);\r
 \r
+  //\r
+  // Get HTTP timeout value\r
+  //\r
+  TimeoutValue = PcdGet32 (PcdHttpIoTimeout);\r
+\r
   ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));\r
   if (!Private->UsingIpv6) {\r
     ConfigData.Config4.HttpVersion    = HttpVersion11;\r
-    ConfigData.Config4.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
+    ConfigData.Config4.RequestTimeOut = TimeoutValue;\r
     IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4);\r
     IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4);\r
+    ImageHandle = Private->Ip4Nic->ImageHandle;\r
   } else {\r
     ConfigData.Config6.HttpVersion    = HttpVersion11;\r
-    ConfigData.Config6.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
+    ConfigData.Config6.RequestTimeOut = TimeoutValue;\r
     IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);\r
+    ImageHandle = Private->Ip6Nic->ImageHandle;\r
   }\r
 \r
   Status = HttpIoCreateIo (\r
-             Private->Image,\r
+             ImageHandle,\r
              Private->Controller,\r
              Private->UsingIpv6 ? IP_VERSION_6 : IP_VERSION_4,\r
              &ConfigData,\r
+             HttpBootHttpIoCallback,\r
+             (VOID *)Private,\r
              &Private->HttpIo\r
              );\r
   if (EFI_ERROR (Status)) {\r
@@ -464,13 +661,13 @@ HttpBootCreateHttpIo (
 **/\r
 VOID\r
 HttpBootFreeCache (\r
-  IN  HTTP_BOOT_CACHE_CONTENT    *Cache\r
+  IN  HTTP_BOOT_CACHE_CONTENT  *Cache\r
   )\r
 {\r
-  UINTN                       Index;\r
-  LIST_ENTRY                  *Entry;\r
-  LIST_ENTRY                  *NextEntry;\r
-  HTTP_BOOT_ENTITY_DATA       *EntityData;\r
+  UINTN                  Index;\r
+  LIST_ENTRY             *Entry;\r
+  LIST_ENTRY             *NextEntry;\r
+  HTTP_BOOT_ENTITY_DATA  *EntityData;\r
 \r
   if (Cache != NULL) {\r
     //\r
@@ -480,6 +677,7 @@ HttpBootFreeCache (
       if (Cache->RequestData->Url != NULL) {\r
         FreePool (Cache->RequestData->Url);\r
       }\r
+\r
       FreePool (Cache->RequestData);\r
     }\r
 \r
@@ -492,6 +690,7 @@ HttpBootFreeCache (
           FreePool (Cache->ResponseData->Headers[Index].FieldName);\r
           FreePool (Cache->ResponseData->Headers[Index].FieldValue);\r
         }\r
+\r
         FreePool (Cache->ResponseData->Headers);\r
       }\r
     }\r
@@ -504,6 +703,7 @@ HttpBootFreeCache (
       if (EntityData->Block != NULL) {\r
         FreePool (EntityData->Block);\r
       }\r
+\r
       RemoveEntryList (&EntityData->Link);\r
       FreePool (EntityData);\r
     }\r
@@ -520,13 +720,13 @@ HttpBootFreeCache (
 **/\r
 VOID\r
 HttpBootFreeCacheList (\r
-  IN     HTTP_BOOT_PRIVATE_DATA   *Private\r
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private\r
   )\r
 {\r
-  LIST_ENTRY                  *Entry;\r
-  LIST_ENTRY                  *NextEntry;\r
-  HTTP_BOOT_CACHE_CONTENT     *Cache;\r
-  \r
+  LIST_ENTRY               *Entry;\r
+  LIST_ENTRY               *NextEntry;\r
+  HTTP_BOOT_CACHE_CONTENT  *Cache;\r
+\r
   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->CacheList) {\r
     Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);\r
     RemoveEntryList (&Cache->Link);\r
@@ -546,6 +746,7 @@ HttpBootFreeCacheList (
   @param[out]         Buffer          The memory buffer to transfer the file to. IF Buffer is NULL,\r
                                       then the size of the requested file is returned in\r
                                       BufferSize.\r
+  @param[out]         ImageType       The image type of the downloaded file.\r
 \r
   @retval EFI_SUCCESS          Successfully created.\r
   @retval Others               Failed to create HttpIo.\r
@@ -553,26 +754,23 @@ HttpBootFreeCacheList (
 **/\r
 EFI_STATUS\r
 HttpBootGetFileFromCache (\r
-  IN     HTTP_BOOT_PRIVATE_DATA   *Private,\r
-  IN     CHAR16                   *Uri,\r
-  IN OUT UINTN                    *BufferSize,\r
-     OUT UINT8                    *Buffer\r
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private,\r
+  IN     CHAR16                  *Uri,\r
+  IN OUT UINTN                   *BufferSize,\r
+  OUT UINT8                      *Buffer,\r
+  OUT HTTP_BOOT_IMAGE_TYPE       *ImageType\r
   )\r
 {\r
-  LIST_ENTRY                  *Entry;\r
-  LIST_ENTRY                  *Entry2;\r
-  HTTP_BOOT_CACHE_CONTENT     *Cache;\r
-  HTTP_BOOT_ENTITY_DATA       *EntityData;\r
-  UINTN                       CopyedSize;\r
-  \r
-  if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {\r
+  LIST_ENTRY               *Entry;\r
+  LIST_ENTRY               *Entry2;\r
+  HTTP_BOOT_CACHE_CONTENT  *Cache;\r
+  HTTP_BOOT_ENTITY_DATA    *EntityData;\r
+  UINTN                    CopyedSize;\r
+\r
+  if ((Uri == NULL) || (BufferSize == NULL) || (Buffer == NULL) || (ImageType == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  //\r
-  // Search file in the cache list, the cache entry will be released upon a successful\r
-  // match.\r
-  //\r
   NET_LIST_FOR_EACH (Entry, &Private->CacheList) {\r
     Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);\r
     //\r
@@ -580,10 +778,15 @@ HttpBootGetFileFromCache (
     //\r
     if ((Cache->RequestData != NULL) &&\r
         (Cache->RequestData->Url != NULL) &&\r
-        (StrCmp (Uri, Cache->RequestData->Url) == 0)) \r
+        (StrCmp (Uri, Cache->RequestData->Url) == 0))\r
     {\r
       //\r
-      // Hit cache, check buffer size.\r
+      // Hit in cache, record image type.\r
+      //\r
+      *ImageType = Cache->ImageType;\r
+\r
+      //\r
+      // Check buffer size.\r
       //\r
       if (*BufferSize < Cache->EntityLength) {\r
         *BufferSize = Cache->EntityLength;\r
@@ -606,12 +809,6 @@ HttpBootGetFileFromCache (
         }\r
       }\r
       *BufferSize = CopyedSize;\r
-\r
-      //\r
-      // On success, free the cached data to release the memory resource.\r
-      //\r
-      RemoveEntryList (&Cache->Link);\r
-      HttpBootFreeCache (Cache);\r
       return EFI_SUCCESS;\r
     }\r
   }\r
@@ -632,19 +829,21 @@ HttpBootGetFileFromCache (
 \r
   @retval EFI_SUCCESS              Continue to parser the message body.\r
   @retval Others                   Abort the parse.\r
\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 HttpBootGetBootFileCallback (\r
-  IN HTTP_BODY_PARSE_EVENT      EventType,\r
-  IN CHAR8                      *Data,\r
-  IN UINTN                      Length,\r
-  IN VOID                       *Context\r
+  IN HTTP_BODY_PARSE_EVENT  EventType,\r
+  IN CHAR8                  *Data,\r
+  IN UINTN                  Length,\r
+  IN VOID                   *Context\r
   )\r
 {\r
-  HTTP_BOOT_CALLBACK_DATA      *CallbackData;\r
-  HTTP_BOOT_ENTITY_DATA        *NewEntityData;\r
+  HTTP_BOOT_CALLBACK_DATA          *CallbackData;\r
+  HTTP_BOOT_ENTITY_DATA            *NewEntityData;\r
+  EFI_STATUS                       Status;\r
+  EFI_HTTP_BOOT_CALLBACK_PROTOCOL  *HttpBootCallback;\r
 \r
   //\r
   // We only care about the entity data.\r
@@ -653,7 +852,21 @@ HttpBootGetBootFileCallback (
     return EFI_SUCCESS;\r
   }\r
 \r
-  CallbackData = (HTTP_BOOT_CALLBACK_DATA *) Context;\r
+  CallbackData     = (HTTP_BOOT_CALLBACK_DATA *)Context;\r
+  HttpBootCallback = CallbackData->Private->HttpBootCallback;\r
+  if (HttpBootCallback != NULL) {\r
+    Status = HttpBootCallback->Callback (\r
+                                 HttpBootCallback,\r
+                                 HttpBootHttpEntityBody,\r
+                                 TRUE,\r
+                                 (UINT32)Length,\r
+                                 Data\r
+                                 );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
   //\r
   // Copy data if caller has provided a buffer.\r
   //\r
@@ -674,20 +887,23 @@ HttpBootGetBootFileCallback (
     if (NewEntityData == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
+\r
     if (CallbackData->NewBlock) {\r
       NewEntityData->Block = CallbackData->Block;\r
-      CallbackData->Block = NULL;\r
+      CallbackData->Block  = NULL;\r
     }\r
+\r
     NewEntityData->DataLength = Length;\r
-    NewEntityData->DataStart  = (UINT8*) Data;\r
+    NewEntityData->DataStart  = (UINT8 *)Data;\r
     InsertTailList (&CallbackData->Cache->EntityDataList, &NewEntityData->Link);\r
   }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
   This function download the boot file by using UEFI HTTP protocol.\r
-  \r
+\r
   @param[in]       Private         The pointer to the driver's private data.\r
   @param[in]       HeaderOnly      Only request the response header, it could save a lot of time if\r
                                    the caller only want to know the size of the requested file.\r
@@ -698,6 +914,7 @@ HttpBootGetBootFileCallback (
   @param[out]      Buffer          The memory buffer to transfer the file to. IF Buffer is NULL,\r
                                    then the size of the requested file is returned in\r
                                    BufferSize.\r
+  @param[out]      ImageType       The image type of the downloaded file.\r
 \r
   @retval EFI_SUCCESS              The file was loaded.\r
   @retval EFI_INVALID_PARAMETER    BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL.\r
@@ -705,54 +922,63 @@ HttpBootGetBootFileCallback (
   @retval EFI_BUFFER_TOO_SMALL     The BufferSize is too small to read the current directory entry.\r
                                    BufferSize has been updated with the size needed to complete\r
                                    the request.\r
+  @retval EFI_ACCESS_DENIED        The server needs to authenticate the client.\r
   @retval Others                   Unexpected error happened.\r
 \r
 **/\r
 EFI_STATUS\r
 HttpBootGetBootFile (\r
-  IN     HTTP_BOOT_PRIVATE_DATA   *Private,\r
-  IN     BOOLEAN                  HeaderOnly,\r
-  IN OUT UINTN                    *BufferSize,\r
-     OUT UINT8                    *Buffer\r
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private,\r
+  IN     BOOLEAN                 HeaderOnly,\r
+  IN OUT UINTN                   *BufferSize,\r
+  OUT UINT8                      *Buffer,\r
+  OUT HTTP_BOOT_IMAGE_TYPE       *ImageType\r
   )\r
 {\r
-  EFI_STATUS                 Status;\r
-  CHAR8                      *HostName;\r
-  EFI_HTTP_REQUEST_DATA      *RequestData;\r
-  HTTP_IO_RESPONSE_DATA      *ResponseData;\r
-  HTTP_IO_RESPONSE_DATA      ResponseBody;\r
-  HTTP_IO                    *HttpIo;\r
-  HTTP_IO_HEADER             *HttpIoHeader;\r
-  VOID                       *Parser;\r
-  HTTP_BOOT_CALLBACK_DATA    Context;\r
-  UINTN                      ContentLength;\r
-  HTTP_BOOT_CACHE_CONTENT    *Cache;\r
-  UINT8                      *Block;\r
-  CHAR16                     *Url;\r
-  BOOLEAN                    IdentityMode;\r
-  UINTN                      ReceivedSize;\r
-  \r
+  EFI_STATUS               Status;\r
+  EFI_HTTP_STATUS_CODE     StatusCode;\r
+  CHAR8                    *HostName;\r
+  EFI_HTTP_REQUEST_DATA    *RequestData;\r
+  HTTP_IO_RESPONSE_DATA    *ResponseData;\r
+  HTTP_IO_RESPONSE_DATA    ResponseBody;\r
+  HTTP_IO                  *HttpIo;\r
+  HTTP_IO_HEADER           *HttpIoHeader;\r
+  VOID                     *Parser;\r
+  HTTP_BOOT_CALLBACK_DATA  Context;\r
+  UINTN                    ContentLength;\r
+  HTTP_BOOT_CACHE_CONTENT  *Cache;\r
+  UINT8                    *Block;\r
+  UINTN                    UrlSize;\r
+  CHAR16                   *Url;\r
+  BOOLEAN                  IdentityMode;\r
+  UINTN                    ReceivedSize;\r
+  CHAR8                    BaseAuthValue[80];\r
+  EFI_HTTP_HEADER          *HttpHeader;\r
+  CHAR8                    *Data;\r
+\r
   ASSERT (Private != NULL);\r
   ASSERT (Private->HttpCreated);\r
 \r
-  if (BufferSize == NULL) {\r
+  if ((BufferSize == NULL) || (ImageType == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (*BufferSize != 0 && Buffer == NULL) {\r
+  if ((*BufferSize != 0) && (Buffer == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
   // First, check whether we already cached the requested Uri.\r
   //\r
-  Url = AllocatePool ((AsciiStrLen (Private->BootFileUri) + 1) * sizeof (CHAR16));\r
+  UrlSize = AsciiStrSize (Private->BootFileUri);\r
+  Url     = AllocatePool (UrlSize * sizeof (CHAR16));\r
   if (Url == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  AsciiStrToUnicodeStr (Private->BootFileUri, Url);\r
-  if (!HeaderOnly) {\r
-    Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer);\r
+\r
+  AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize);\r
+  if (!HeaderOnly && (Buffer != NULL)) {\r
+    Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer, ImageType);\r
     if (Status != EFI_NOT_FOUND) {\r
       FreePool (Url);\r
       return Status;\r
@@ -773,6 +999,8 @@ HttpBootGetBootFile (
       Status = EFI_OUT_OF_RESOURCES;\r
       goto ERROR_1;\r
     }\r
+\r
+    Cache->ImageType = ImageTypeMax;\r
     InitializeListHead (&Cache->EntityDataList);\r
   }\r
 \r
@@ -785,8 +1013,9 @@ HttpBootGetBootFile (
   //       Host\r
   //       Accept\r
   //       User-Agent\r
+  //       [Authorization]\r
   //\r
-  HttpIoHeader = HttpBootCreateHeader (3);\r
+  HttpIoHeader = HttpIoCreateHeader ((Private->AuthData != NULL) ? 4 : 3);\r
   if (HttpIoHeader == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ERROR_2;\r
@@ -796,17 +1025,18 @@ HttpBootGetBootFile (
   // Add HTTP header field 1: Host\r
   //\r
   HostName = NULL;\r
-  Status = HttpUrlGetHostName (\r
-             Private->BootFileUri,\r
-             Private->BootFileUriParser,\r
-             &HostName\r
-             );\r
+  Status   = HttpUrlGetHostName (\r
+               Private->BootFileUri,\r
+               Private->BootFileUriParser,\r
+               &HostName\r
+               );\r
   if (EFI_ERROR (Status)) {\r
     goto ERROR_3;\r
   }\r
-  Status = HttpBootSetHeader (\r
+\r
+  Status = HttpIoSetHeader (\r
              HttpIoHeader,\r
-             HTTP_FIELD_NAME_HOST,\r
+             HTTP_HEADER_HOST,\r
              HostName\r
              );\r
   FreePool (HostName);\r
@@ -817,9 +1047,9 @@ HttpBootGetBootFile (
   //\r
   // Add HTTP header field 2: Accept\r
   //\r
-  Status = HttpBootSetHeader (\r
+  Status = HttpIoSetHeader (\r
              HttpIoHeader,\r
-             HTTP_FIELD_NAME_ACCEPT,\r
+             HTTP_HEADER_ACCEPT,\r
              "*/*"\r
              );\r
   if (EFI_ERROR (Status)) {\r
@@ -829,15 +1059,44 @@ HttpBootGetBootFile (
   //\r
   // Add HTTP header field 3: User-Agent\r
   //\r
-  Status = HttpBootSetHeader (\r
+  Status = HttpIoSetHeader (\r
              HttpIoHeader,\r
-             HTTP_FIELD_NAME_USER_AGENT,\r
+             HTTP_HEADER_USER_AGENT,\r
              HTTP_USER_AGENT_EFI_HTTP_BOOT\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto ERROR_3;\r
   }\r
 \r
+  //\r
+  // Add HTTP header field 4: Authorization\r
+  //\r
+  if (Private->AuthData != NULL) {\r
+    ASSERT (HttpIoHeader->MaxHeaderCount == 4);\r
+\r
+    if ((Private->AuthScheme != NULL) && (CompareMem (Private->AuthScheme, "Basic", 5) != 0)) {\r
+      Status = EFI_UNSUPPORTED;\r
+      goto ERROR_3;\r
+    }\r
+\r
+    AsciiSPrint (\r
+      BaseAuthValue,\r
+      sizeof (BaseAuthValue),\r
+      "%a %a",\r
+      "Basic",\r
+      Private->AuthData\r
+      );\r
+\r
+    Status = HttpIoSetHeader (\r
+               HttpIoHeader,\r
+               HTTP_HEADER_AUTHORIZATION,\r
+               BaseAuthValue\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR_3;\r
+    }\r
+  }\r
+\r
   //\r
   // 2.2 Build the rest of HTTP request info.\r
   //\r
@@ -846,13 +1105,9 @@ HttpBootGetBootFile (
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ERROR_3;\r
   }\r
+\r
   RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet;\r
-  RequestData->Url = Url;\r
-  if (RequestData->Url == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ERROR_4;\r
-  }\r
-  AsciiStrToUnicodeStr (Private->BootFileUri, RequestData->Url);\r
+  RequestData->Url    = Url;\r
 \r
   //\r
   // 2.3 Record the request info in a temp cache item.\r
@@ -872,7 +1127,7 @@ HttpBootGetBootFile (
              HttpIoHeader->Headers,\r
              0,\r
              NULL\r
-            );\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     goto ERROR_4;\r
   }\r
@@ -884,16 +1139,100 @@ HttpBootGetBootFile (
   //\r
   // 3.1 First step, use zero BodyLength to only receive the response headers.\r
   //\r
-  ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESPONSE_DATA));\r
+  ResponseData = AllocateZeroPool (sizeof (HTTP_IO_RESPONSE_DATA));\r
   if (ResponseData == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ERROR_4;\r
   }\r
+\r
+  Data   = NULL;\r
   Status = HttpIoRecvResponse (\r
              &Private->HttpIo,\r
              TRUE,\r
              ResponseData\r
              );\r
+  if (EFI_ERROR (Status) || EFI_ERROR (ResponseData->Status)) {\r
+    if (EFI_ERROR (ResponseData->Status)) {\r
+      StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode;\r
+      HttpBootPrintErrorMessage (StatusCode);\r
+      Status = ResponseData->Status;\r
+      if ((StatusCode == HTTP_STATUS_401_UNAUTHORIZED) || \\r
+          (StatusCode == HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED))\r
+      {\r
+        if ((Private->AuthData != NULL) || (Private->AuthScheme != NULL)) {\r
+          if (Private->AuthData != NULL) {\r
+            FreePool (Private->AuthData);\r
+            Private->AuthData = NULL;\r
+          }\r
+\r
+          if (Private->AuthScheme != NULL) {\r
+            FreePool (Private->AuthScheme);\r
+            Private->AuthScheme = NULL;\r
+          }\r
+\r
+          Status = EFI_ACCESS_DENIED;\r
+          goto ERROR_4;\r
+        }\r
+\r
+        //\r
+        // Server indicates the user has to provide a user-id and password as a means of identification.\r
+        //\r
+        if (Private->HttpBootCallback != NULL) {\r
+          Data = AllocateZeroPool (sizeof (CHAR8) * HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN);\r
+          if (Data == NULL) {\r
+            Status = EFI_OUT_OF_RESOURCES;\r
+            goto ERROR_4;\r
+          }\r
+\r
+          Status = Private->HttpBootCallback->Callback (\r
+                                                Private->HttpBootCallback,\r
+                                                HttpBootHttpAuthInfo,\r
+                                                TRUE,\r
+                                                HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN,\r
+                                                Data\r
+                                                );\r
+          if (EFI_ERROR (Status)) {\r
+            if (Data != NULL) {\r
+              FreePool (Data);\r
+            }\r
+\r
+            goto ERROR_5;\r
+          }\r
+\r
+          Private->AuthData = (CHAR8 *)Data;\r
+        }\r
+\r
+        HttpHeader = HttpFindHeader (\r
+                       ResponseData->HeaderCount,\r
+                       ResponseData->Headers,\r
+                       HTTP_HEADER_WWW_AUTHENTICATE\r
+                       );\r
+        if (HttpHeader != NULL) {\r
+          Private->AuthScheme = AllocateZeroPool (AsciiStrLen (HttpHeader->FieldValue) + 1);\r
+          if (Private->AuthScheme == NULL) {\r
+            return EFI_OUT_OF_RESOURCES;\r
+          }\r
+\r
+          CopyMem (Private->AuthScheme, HttpHeader->FieldValue, AsciiStrLen (HttpHeader->FieldValue));\r
+        }\r
+\r
+        Status = EFI_ACCESS_DENIED;\r
+      }\r
+    }\r
+\r
+    goto ERROR_5;\r
+  }\r
+\r
+  //\r
+  // Check the image type according to server's response.\r
+  //\r
+  Status = HttpBootCheckImageType (\r
+             Private->BootFileUri,\r
+             Private->BootFileUriParser,\r
+             ResponseData->HeaderCount,\r
+             ResponseData->Headers,\r
+             ImageType\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     goto ERROR_5;\r
   }\r
@@ -903,27 +1242,29 @@ HttpBootGetBootFile (
   //\r
   if (Cache != NULL) {\r
     Cache->ResponseData = ResponseData;\r
+    Cache->ImageType    = *ImageType;\r
   }\r
-  \r
+\r
   //\r
   // 3.3 Init a message-body parser from the header information.\r
   //\r
-  Parser = NULL;\r
+  Parser             = NULL;\r
   Context.NewBlock   = FALSE;\r
   Context.Block      = NULL;\r
   Context.CopyedSize = 0;\r
   Context.Buffer     = Buffer;\r
   Context.BufferSize = *BufferSize;\r
   Context.Cache      = Cache;\r
-  Status = HttpInitMsgParser (\r
-             HeaderOnly? HttpMethodHead : HttpMethodGet,\r
-             ResponseData->Response.StatusCode,\r
-             ResponseData->HeaderCount,\r
-             ResponseData->Headers,\r
-             HttpBootGetBootFileCallback,\r
-             (VOID*) &Context,\r
-             &Parser\r
-             );\r
+  Context.Private    = Private;\r
+  Status             = HttpInitMsgParser (\r
+                         HeaderOnly ? HttpMethodHead : HttpMethodGet,\r
+                         ResponseData->Response.StatusCode,\r
+                         ResponseData->HeaderCount,\r
+                         ResponseData->Headers,\r
+                         HttpBootGetBootFileCallback,\r
+                         (VOID *)&Context,\r
+                         &Parser\r
+                         );\r
   if (EFI_ERROR (Status)) {\r
     goto ERROR_6;\r
   }\r
@@ -937,7 +1278,7 @@ HttpBootGetBootFile (
     // 3.4.1, check whether we are in identity transfer-coding.\r
     //\r
     ContentLength = 0;\r
-    Status = HttpGetEntityLength (Parser, &ContentLength);\r
+    Status        = HttpGetEntityLength (Parser, &ContentLength);\r
     if (!EFI_ERROR (Status)) {\r
       IdentityMode = TRUE;\r
     } else {\r
@@ -956,17 +1297,34 @@ HttpBootGetBootFile (
       //\r
       ReceivedSize = 0;\r
       while (ReceivedSize < ContentLength) {\r
-        ResponseBody.Body       = (CHAR8*) Buffer + ReceivedSize;\r
+        ResponseBody.Body       = (CHAR8 *)Buffer + ReceivedSize;\r
         ResponseBody.BodyLength = *BufferSize - ReceivedSize;\r
-        Status = HttpIoRecvResponse (\r
-                   &Private->HttpIo,\r
-                   FALSE,\r
-                   &ResponseBody\r
-                   );\r
-        if (EFI_ERROR (Status)) {\r
+        Status                  = HttpIoRecvResponse (\r
+                                    &Private->HttpIo,\r
+                                    FALSE,\r
+                                    &ResponseBody\r
+                                    );\r
+        if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {\r
+          if (EFI_ERROR (ResponseBody.Status)) {\r
+            Status = ResponseBody.Status;\r
+          }\r
+\r
           goto ERROR_6;\r
         }\r
+\r
         ReceivedSize += ResponseBody.BodyLength;\r
+        if (Private->HttpBootCallback != NULL) {\r
+          Status = Private->HttpBootCallback->Callback (\r
+                                                Private->HttpBootCallback,\r
+                                                HttpBootHttpEntityBody,\r
+                                                TRUE,\r
+                                                (UINT32)ResponseBody.BodyLength,\r
+                                                ResponseBody.Body\r
+                                                );\r
+          if (EFI_ERROR (Status)) {\r
+            goto ERROR_6;\r
+          }\r
+        }\r
       }\r
     } else {\r
       //\r
@@ -981,26 +1339,31 @@ HttpBootGetBootFile (
         // Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before\r
         // every HttpIoRecvResponse().\r
         //\r
-        if (Block == NULL || Context.BufferSize == 0) {\r
+        if ((Block == NULL) || (Context.BufferSize == 0)) {\r
           Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);\r
           if (Block == NULL) {\r
             Status = EFI_OUT_OF_RESOURCES;\r
             goto ERROR_6;\r
           }\r
+\r
           Context.NewBlock = TRUE;\r
-          Context.Block = Block;\r
+          Context.Block    = Block;\r
         } else {\r
           Context.NewBlock = FALSE;\r
         }\r
 \r
-        ResponseBody.Body       = (CHAR8*) Block;\r
+        ResponseBody.Body       = (CHAR8 *)Block;\r
         ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;\r
-        Status = HttpIoRecvResponse (\r
-                   &Private->HttpIo,\r
-                   FALSE,\r
-                   &ResponseBody\r
-                   );\r
-        if (EFI_ERROR (Status)) {\r
+        Status                  = HttpIoRecvResponse (\r
+                                    &Private->HttpIo,\r
+                                    FALSE,\r
+                                    &ResponseBody\r
+                                    );\r
+        if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {\r
+          if (EFI_ERROR (ResponseBody.Status)) {\r
+            Status = ResponseBody.Status;\r
+          }\r
+\r
           goto ERROR_6;\r
         }\r
 \r
@@ -1029,7 +1392,10 @@ HttpBootGetBootFile (
 \r
   if (*BufferSize < ContentLength) {\r
     Status = EFI_BUFFER_TOO_SMALL;\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
   }\r
+\r
   *BufferSize = ContentLength;\r
 \r
   //\r
@@ -1044,31 +1410,36 @@ HttpBootGetBootFile (
     HttpFreeMsgParser (Parser);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
-  \r
+  return Status;\r
+\r
 ERROR_6:\r
   if (Parser != NULL) {\r
     HttpFreeMsgParser (Parser);\r
   }\r
+\r
   if (Context.Block != NULL) {\r
     FreePool (Context.Block);\r
   }\r
+\r
   HttpBootFreeCache (Cache);\r
-  \r
+\r
 ERROR_5:\r
   if (ResponseData != NULL) {\r
     FreePool (ResponseData);\r
   }\r
+\r
 ERROR_4:\r
   if (RequestData != NULL) {\r
     FreePool (RequestData);\r
   }\r
+\r
 ERROR_3:\r
-  HttpBootFreeHeader (HttpIoHeader);\r
+  HttpIoFreeHeader (HttpIoHeader);\r
 ERROR_2:\r
   if (Cache != NULL) {\r
     FreePool (Cache);\r
   }\r
+\r
 ERROR_1:\r
   if (Url != NULL) {\r
     FreePool (Url);\r