]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
NetworkPkg: Check allocated buffer pointer before use.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
index 41d3d30a12d50c563a3935cd68e7d8fa082bc486..327b4cf1cfc5fc0f3e1ef388d51e05e188871756 100644 (file)
@@ -2,7 +2,7 @@
   Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
 \r
   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
   Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
 \r
   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
-  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -93,10 +93,12 @@ PxeBcBuildDhcp6Options (
   // Append client option request option\r
   //\r
   OptList[Index]->OpCode     = HTONS (DHCP6_OPT_ORO);\r
   // Append client option request option\r
   //\r
   OptList[Index]->OpCode     = HTONS (DHCP6_OPT_ORO);\r
-  OptList[Index]->OpLen      = HTONS (4);\r
+  OptList[Index]->OpLen      = HTONS (8);\r
   OptEnt.Oro                 = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
   OptEnt.Oro->OpCode[0]      = HTONS(DHCP6_OPT_BOOT_FILE_URL);\r
   OptEnt.Oro->OpCode[1]      = HTONS(DHCP6_OPT_BOOT_FILE_PARAM);\r
   OptEnt.Oro                 = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
   OptEnt.Oro->OpCode[0]      = HTONS(DHCP6_OPT_BOOT_FILE_URL);\r
   OptEnt.Oro->OpCode[1]      = HTONS(DHCP6_OPT_BOOT_FILE_PARAM);\r
+  OptEnt.Oro->OpCode[2]      = HTONS(DHCP6_OPT_DNS_SERVERS);\r
+  OptEnt.Oro->OpCode[3]      = HTONS(DHCP6_OPT_VENDOR_CLASS);\r
   Index++;\r
   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
 \r
   Index++;\r
   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
 \r
@@ -180,17 +182,24 @@ PxeBcBuildDhcp6Options (
   @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
   @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
+  @retval     EFI_SUCCESS                Packet is copied.\r
+  @retval     EFI_BUFFER_TOO_SMALL       Cache buffer is not big enough to hold the packet.\r
+\r
 **/\r
 **/\r
-VOID\r
+EFI_STATUS\r
 PxeBcCacheDhcp6Packet (\r
   IN EFI_DHCP6_PACKET          *Dst,\r
   IN EFI_DHCP6_PACKET          *Src\r
   )\r
 {\r
 PxeBcCacheDhcp6Packet (\r
   IN EFI_DHCP6_PACKET          *Dst,\r
   IN EFI_DHCP6_PACKET          *Src\r
   )\r
 {\r
-  ASSERT (Dst->Size >= Src->Length);\r
+  if (Dst->Size < Src->Length) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
 \r
   CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
   Dst->Length = Src->Length;\r
 \r
   CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
   Dst->Length = Src->Length;\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
 }\r
 \r
 \r
@@ -216,10 +225,173 @@ PxeBcFreeBootFileOption (
   }\r
 }\r
 \r
   }\r
 }\r
 \r
+/**\r
+  Retrieve the boot server address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  Private             Pointer to PxeBc 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_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
+PxeBcDns6 (\r
+  IN PXEBC_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_IPv6_ADDRESS                *DnsServerList;\r
+  BOOLEAN                         IsDone;\r
+  \r
+  Dns6                = NULL;\r
+  Dns6Handle          = NULL;\r
+  DnsServerList       = Private->DnsServer;\r
+  ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\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 = 1;\r
+  Dns6ConfigData.DnsServerList  = DnsServerList;\r
+  Dns6ConfigData.EnableDnsCache = TRUE;\r
+  Dns6ConfigData.Protocol       = EFI_IP_PROTO_UDP;\r
+  IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.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
+                  PxeBcCommonNotify,\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
+  FreePool (HostName);\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
 /**\r
   Parse the Boot File URL option.\r
 \r
 \r
 /**\r
   Parse the Boot File URL option.\r
 \r
+  @param[in]      Private      Pointer to PxeBc private data.\r
   @param[out]     FileName     The pointer to the boot file name.\r
   @param[in, out] SrvAddr      The pointer to the boot server address.\r
   @param[in]      BootFile     The pointer to the boot file URL option data.\r
   @param[out]     FileName     The pointer to the boot file name.\r
   @param[in, out] SrvAddr      The pointer to the boot server address.\r
   @param[in]      BootFile     The pointer to the boot file URL option data.\r
@@ -232,6 +404,7 @@ PxeBcFreeBootFileOption (
 **/\r
 EFI_STATUS\r
 PxeBcExtractBootFileUrl (\r
 **/\r
 EFI_STATUS\r
 PxeBcExtractBootFileUrl (\r
+  IN PXEBC_PRIVATE_DATA      *Private,\r
      OUT UINT8               **FileName,\r
   IN OUT EFI_IPv6_ADDRESS    *SrvAddr,\r
   IN     CHAR8               *BootFile,\r
      OUT UINT8               **FileName,\r
   IN OUT EFI_IPv6_ADDRESS    *SrvAddr,\r
   IN     CHAR8               *BootFile,\r
@@ -247,8 +420,12 @@ PxeBcExtractBootFileUrl (
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
   CHAR8                      *ModeStr;\r
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
   CHAR8                      *ModeStr;\r
+  CHAR16                     *HostName;\r
+  BOOLEAN                    IpExpressedUrl;\r
+  UINTN                      Len;\r
   EFI_STATUS                 Status;\r
 \r
   EFI_STATUS                 Status;\r
 \r
+  IpExpressedUrl = TRUE;\r
   //\r
   // The format of the Boot File URL option is:\r
   //\r
   //\r
   // The format of the Boot File URL option is:\r
   //\r
@@ -264,8 +441,8 @@ PxeBcExtractBootFileUrl (
   //\r
 \r
   //\r
   //\r
 \r
   //\r
-  // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format\r
-  // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME\r
+  // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be\r
+  // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME\r
   // As an example where the BOOTFILE_NAME is the EFI loader and\r
   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
   //\r
   // As an example where the BOOTFILE_NAME is the EFI loader and\r
   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
   //\r
@@ -291,43 +468,76 @@ PxeBcExtractBootFileUrl (
   // Get the part of SERVER_ADDRESS string.\r
   //\r
   ServerAddressOption = TmpStr;\r
   // Get the part of SERVER_ADDRESS string.\r
   //\r
   ServerAddressOption = TmpStr;\r
-  if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) {\r
+    ServerAddressOption ++;\r
+    ServerAddress = ServerAddressOption;\r
+    while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
+      ServerAddress++;\r
+    }\r
+    \r
+    if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    \r
+    *ServerAddress = '\0';\r
+    \r
+    //\r
+    // Convert the string of server address to Ipv6 address format and store it.\r
+    //\r
+    Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (TmpStr);\r
+      return Status;\r
+    }\r
 \r
 \r
-  ServerAddressOption ++;\r
-  ServerAddress = ServerAddressOption;\r
-  while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
-    ServerAddress++;\r
-  }\r
+  } else {\r
+    IpExpressedUrl = FALSE;\r
+    ServerAddress = ServerAddressOption;\r
+    while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
+      ServerAddress++;\r
+    }\r
 \r
 \r
-  if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+    if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    *ServerAddress = '\0';\r
 \r
 \r
-  *ServerAddress = '\0';\r
+    Len = AsciiStrSize (ServerAddressOption);\r
+    HostName = AllocateZeroPool (Len * sizeof (CHAR16));\r
+    if (HostName == NULL) {\r
+      FreePool (TmpStr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    AsciiStrToUnicodeStrS (\r
+      ServerAddressOption,\r
+      HostName,\r
+      Len\r
+      );\r
 \r
 \r
-  //\r
-  // Convert the string of server address to Ipv6 address format and store it.\r
-  //\r
-  Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (TmpStr);\r
-    return Status;\r
+    //\r
+    // Perform DNS resolution.\r
+    //\r
+    Status = PxeBcDns6 (Private,HostName, SrvAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (TmpStr);\r
+      return Status;\r
+    }\r
   }\r
 \r
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
   BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);\r
   }\r
 \r
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
   BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);\r
-  if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
+  if (IpExpressedUrl) {\r
+    if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    ++BootFileNamePtr;\r
   }\r
 \r
   }\r
 \r
-  ++BootFileNamePtr;\r
   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
   if (BootFileNameLen != 0 || FileName != NULL) {\r
     //\r
   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
   if (BootFileNameLen != 0 || FileName != NULL) {\r
     //\r
@@ -482,6 +692,8 @@ PxeBcParseDhcp6Packet (
       Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
     } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
       Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;\r
       Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
     } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
       Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;\r
+    } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {\r
+      Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option;\r
     }\r
 \r
     Offset += (NTOHS (Option->OpLen) + 4);\r
     }\r
 \r
     Offset += (NTOHS (Option->OpLen) + 4);\r
@@ -545,8 +757,11 @@ PxeBcParseDhcp6Packet (
   @param[in]  Ack                 The pointer to the DHCPv6 ack packet.\r
   @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.\r
 \r
   @param[in]  Ack                 The pointer to the DHCPv6 ack packet.\r
   @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.\r
 \r
+  @retval     EFI_SUCCESS                Cache and parse the packet successfully.\r
+  @retval     EFI_BUFFER_TOO_SMALL       Cache buffer is not big enough to hold the packet.\r
+\r
 **/\r
 **/\r
-VOID\r
+EFI_STATUS\r
 PxeBcCopyDhcp6Ack (\r
   IN PXEBC_PRIVATE_DATA   *Private,\r
   IN EFI_DHCP6_PACKET     *Ack,\r
 PxeBcCopyDhcp6Ack (\r
   IN PXEBC_PRIVATE_DATA   *Private,\r
   IN EFI_DHCP6_PACKET     *Ack,\r
@@ -554,10 +769,14 @@ PxeBcCopyDhcp6Ack (
   )\r
 {\r
   EFI_PXE_BASE_CODE_MODE  *Mode;\r
   )\r
 {\r
   EFI_PXE_BASE_CODE_MODE  *Mode;\r
+  EFI_STATUS              Status;\r
 \r
   Mode = Private->PxeBc.Mode;\r
 \r
 \r
   Mode = Private->PxeBc.Mode;\r
 \r
-  PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);\r
+  Status = PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
   if (Verified) {\r
     //\r
 \r
   if (Verified) {\r
     //\r
@@ -567,6 +786,8 @@ PxeBcCopyDhcp6Ack (
     CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);\r
     Mode->DhcpAckReceived = TRUE;\r
   }\r
     CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);\r
     Mode->DhcpAckReceived = TRUE;\r
   }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
 }\r
 \r
 \r
@@ -576,8 +797,11 @@ PxeBcCopyDhcp6Ack (
   @param[in]  Private               The pointer to PxeBc private data.\r
   @param[in]  OfferIndex            The received order of offer packets.\r
 \r
   @param[in]  Private               The pointer to PxeBc private data.\r
   @param[in]  OfferIndex            The received order of offer packets.\r
 \r
+  @retval     EFI_SUCCESS                Cache and parse the packet successfully.\r
+  @retval     EFI_BUFFER_TOO_SMALL       Cache buffer is not big enough to hold the packet.\r
+\r
 **/\r
 **/\r
-VOID\r
+EFI_STATUS\r
 PxeBcCopyDhcp6Proxy (\r
   IN PXEBC_PRIVATE_DATA     *Private,\r
   IN UINT32                 OfferIndex\r
 PxeBcCopyDhcp6Proxy (\r
   IN PXEBC_PRIVATE_DATA     *Private,\r
   IN UINT32                 OfferIndex\r
@@ -585,6 +809,7 @@ PxeBcCopyDhcp6Proxy (
 {\r
   EFI_PXE_BASE_CODE_MODE    *Mode;\r
   EFI_DHCP6_PACKET          *Offer;\r
 {\r
   EFI_PXE_BASE_CODE_MODE    *Mode;\r
   EFI_DHCP6_PACKET          *Offer;\r
+  EFI_STATUS              Status;\r
 \r
   ASSERT (OfferIndex < Private->OfferNum);\r
   ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
 \r
   ASSERT (OfferIndex < Private->OfferNum);\r
   ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
@@ -595,7 +820,10 @@ PxeBcCopyDhcp6Proxy (
   //\r
   // Cache the proxy offer packet and parse it.\r
   //\r
   //\r
   // Cache the proxy offer packet and parse it.\r
   //\r
-  PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);\r
+  Status = PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
   PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);\r
 \r
   //\r
   PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);\r
 \r
   //\r
@@ -603,6 +831,8 @@ PxeBcCopyDhcp6Proxy (
   //\r
   CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);\r
   Mode->ProxyOfferReceived = TRUE;\r
   //\r
   CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);\r
   Mode->ProxyOfferReceived = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -678,12 +908,12 @@ PxeBcRequestBootService (
   UINT16                              OpCode;\r
   UINT16                              OpLen;\r
   EFI_STATUS                          Status;\r
   UINT16                              OpCode;\r
   UINT16                              OpLen;\r
   EFI_STATUS                          Status;\r
-  EFI_DHCP6_PACKET                    *ProxyOffer;\r
+  EFI_DHCP6_PACKET                    *IndexOffer;\r
   UINT8                               *Option;\r
 \r
   PxeBc       = &Private->PxeBc;\r
   Request     = Private->Dhcp6Request;\r
   UINT8                               *Option;\r
 \r
   PxeBc       = &Private->PxeBc;\r
   Request     = Private->Dhcp6Request;\r
-  ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;\r
+  IndexOffer  = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;\r
   SrcPort     = PXEBC_BS_DISCOVER_PORT;\r
   DestPort    = PXEBC_BS_DISCOVER_PORT;\r
   OpFlags     = 0;\r
   SrcPort     = PXEBC_BS_DISCOVER_PORT;\r
   DestPort    = PXEBC_BS_DISCOVER_PORT;\r
   OpFlags     = 0;\r
@@ -700,7 +930,7 @@ PxeBcRequestBootService (
   //\r
   // Build the request packet by the cached request packet before.\r
   //\r
   //\r
   // Build the request packet by the cached request packet before.\r
   //\r
-  Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId;\r
+  Discover->TransactionId = IndexOffer->Dhcp6.Header.TransactionId;\r
   Discover->MessageType   = Request->Dhcp6.Header.MessageType;\r
   RequestOpt              = Request->Dhcp6.Option;\r
   DiscoverOpt             = Discover->DhcpOptions;\r
   Discover->MessageType   = Request->Dhcp6.Header.MessageType;\r
   RequestOpt              = Request->Dhcp6.Option;\r
   DiscoverOpt             = Discover->DhcpOptions;\r
@@ -710,22 +940,24 @@ PxeBcRequestBootService (
   //\r
   // Find Server ID Option from ProxyOffer.\r
   //\r
   //\r
   // Find Server ID Option from ProxyOffer.\r
   //\r
-  Option = PxeBcDhcp6SeekOption (\r
-             ProxyOffer->Dhcp6.Option,\r
-             ProxyOffer->Length - 4,\r
-             DHCP6_OPT_SERVER_ID\r
-             );\r
-  if (Option == NULL) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
+  if (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl) {  \r
+    Option = PxeBcDhcp6SeekOption (\r
+               IndexOffer->Dhcp6.Option,\r
+               IndexOffer->Length - 4,\r
+               DHCP6_OPT_SERVER_ID\r
+               );\r
+    if (Option == NULL) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
   \r
   \r
-  //\r
-  // Add Server ID Option.\r
-  //\r
-  OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen);\r
-  CopyMem (DiscoverOpt, Option, OpLen + 4);\r
-  DiscoverOpt += (OpLen + 4);\r
-  DiscoverLen += (OpLen + 4);\r
+    //\r
+    // Add Server ID Option.\r
+    //\r
+    OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen);\r
+    CopyMem (DiscoverOpt, Option, OpLen + 4);\r
+    DiscoverOpt += (OpLen + 4);\r
+    DiscoverLen += (OpLen + 4);\r
+  }\r
 \r
   while (RequestLen < Request->Length) {\r
     OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);\r
 \r
   while (RequestLen < Request->Length) {\r
     OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);\r
@@ -849,7 +1081,7 @@ PxeBcRetryDhcp6Binl (
   Mode                  = Private->PxeBc.Mode;\r
   Private->IsDoDiscover = FALSE;\r
   Offer                 = &Private->OfferBuffer[Index].Dhcp6;\r
   Mode                  = Private->PxeBc.Mode;\r
   Private->IsDoDiscover = FALSE;\r
   Offer                 = &Private->OfferBuffer[Index].Dhcp6;\r
-  if (Offer->OfferType == PxeOfferTypeDhcpBinl) {\r
+  if (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
     //\r
     // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.\r
     //\r
     //\r
     // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.\r
     //\r
@@ -864,6 +1096,7 @@ PxeBcRetryDhcp6Binl (
     // Parse out the next server address from the last offer, and store it\r
     //\r
     Status = PxeBcExtractBootFileUrl (\r
     // Parse out the next server address from the last offer, and store it\r
     //\r
     Status = PxeBcExtractBootFileUrl (\r
+               Private,\r
                &Private->BootFileName,\r
                &Private->ServerIp.v6,\r
                (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
                &Private->BootFileName,\r
                &Private->ServerIp.v6,\r
                (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
@@ -916,8 +1149,10 @@ PxeBcRetryDhcp6Binl (
   @param[in]  Private               The pointer to PXEBC_PRIVATE_DATA.\r
   @param[in]  RcvdOffer             The pointer to the received offer packet.\r
 \r
   @param[in]  Private               The pointer to PXEBC_PRIVATE_DATA.\r
   @param[in]  RcvdOffer             The pointer to the received offer packet.\r
 \r
+  @retval     EFI_SUCCESS      Cache and parse the packet successfully.\r
+  @retval     Others           Operation failed.\r
 **/\r
 **/\r
-VOID\r
+EFI_STATUS\r
 PxeBcCacheDhcp6Offer (\r
   IN PXEBC_PRIVATE_DATA     *Private,\r
   IN EFI_DHCP6_PACKET       *RcvdOffer\r
 PxeBcCacheDhcp6Offer (\r
   IN PXEBC_PRIVATE_DATA     *Private,\r
   IN EFI_DHCP6_PACKET       *RcvdOffer\r
@@ -926,6 +1161,7 @@ PxeBcCacheDhcp6Offer (
   PXEBC_DHCP6_PACKET_CACHE  *Cache6;\r
   EFI_DHCP6_PACKET          *Offer;\r
   PXEBC_OFFER_TYPE          OfferType;\r
   PXEBC_DHCP6_PACKET_CACHE  *Cache6;\r
   EFI_DHCP6_PACKET          *Offer;\r
   PXEBC_OFFER_TYPE          OfferType;\r
+  EFI_STATUS                Status;\r
 \r
   Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
   Offer  = &Cache6->Packet.Offer;\r
 \r
   Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
   Offer  = &Cache6->Packet.Offer;\r
@@ -933,13 +1169,16 @@ PxeBcCacheDhcp6Offer (
   //\r
   // Cache the content of DHCPv6 packet firstly.\r
   //\r
   //\r
   // Cache the content of DHCPv6 packet firstly.\r
   //\r
-  PxeBcCacheDhcp6Packet (Offer, RcvdOffer);\r
+  Status = PxeBcCacheDhcp6Packet (Offer, RcvdOffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Validate the DHCPv6 packet, and parse the options and offer type.\r
   //\r
   if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {\r
 \r
   //\r
   // Validate the DHCPv6 packet, and parse the options and offer type.\r
   //\r
   if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {\r
-    return ;\r
+    return EFI_ABORTED;\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -961,14 +1200,15 @@ PxeBcCacheDhcp6Offer (
       //\r
       Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
       Private->OfferCount[OfferType]++;\r
       //\r
       Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
       Private->OfferCount[OfferType]++;\r
-    } else if (Private->OfferCount[OfferType] > 0) {\r
+    } else if ((OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeProxyWfm11a) && \r
+                 Private->OfferCount[OfferType] < 1) {\r
       //\r
       // Only cache the first PXE10/WFM11a offer, and discard the others.\r
       //\r
       Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
       Private->OfferCount[OfferType]    = 1;\r
     } else {\r
       //\r
       // Only cache the first PXE10/WFM11a offer, and discard the others.\r
       //\r
       Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
       Private->OfferCount[OfferType]    = 1;\r
     } else {\r
-      return;\r
+      return EFI_ABORTED;\r
     }\r
   } else {\r
     //\r
     }\r
   } else {\r
     //\r
@@ -979,6 +1219,8 @@ PxeBcCacheDhcp6Offer (
   }\r
 \r
   Private->OfferNum++;\r
   }\r
 \r
   Private->OfferNum++;\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
 }\r
 \r
 \r
@@ -1093,8 +1335,10 @@ PxeBcSelectDhcp6Offer (
 \r
   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.\r
 \r
 \r
   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.\r
 \r
-  @retval     EFI_SUCCESS         Handled the DHCPv6 offer packet successfully.\r
-  @retval     EFI_NO_RESPONSE     No response to the following request packet.\r
+  @retval     EFI_SUCCESS           Handled the DHCPv6 offer packet successfully.\r
+  @retval     EFI_NO_RESPONSE       No response to the following request packet.\r
+  @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resources.\r
+  @retval     EFI_BUFFER_TOO_SMALL  Can't cache the offer pacet.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1115,6 +1359,17 @@ PxeBcHandleDhcp6Offer (
   Cache6      = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
   Status      = EFI_SUCCESS;\r
 \r
   Cache6      = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
   Status      = EFI_SUCCESS;\r
 \r
+  //\r
+  // First try to cache DNS server address if DHCP6 offer provides.\r
+  //\r
+  if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) {\r
+    Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen));\r
+    if (Private->DnsServer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS));\r
+  }\r
+\r
   if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
     //\r
     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
   if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
     //\r
     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
@@ -1193,7 +1448,7 @@ PxeBcHandleDhcp6Offer (
         //\r
         // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
         //\r
         //\r
         // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
         //\r
-        PxeBcCopyDhcp6Proxy (Private, ProxyIndex);\r
+        Status = PxeBcCopyDhcp6Proxy (Private, ProxyIndex);\r
       }\r
     } else {\r
       //\r
       }\r
     } else {\r
       //\r
@@ -1207,7 +1462,7 @@ PxeBcHandleDhcp6Offer (
     //\r
     // All PXE boot information is ready by now.\r
     //\r
     //\r
     // All PXE boot information is ready by now.\r
     //\r
-    PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);\r
+    Status = PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);\r
     Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;\r
   }\r
 \r
     Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;\r
   }\r
 \r
@@ -1702,6 +1957,14 @@ PxeBcDhcp6CallBack (
   switch (Dhcp6Event) {\r
 \r
   case Dhcp6SendSolicit:\r
   switch (Dhcp6Event) {\r
 \r
   case Dhcp6SendSolicit:\r
+    if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
+      //\r
+      // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
+      //\r
+      Status = EFI_ABORTED;\r
+      break;\r
+    }\r
+    \r
     //\r
     // Record the first Solicate msg time\r
     //\r
     //\r
     // Record the first Solicate msg time\r
     //\r
@@ -1717,6 +1980,12 @@ PxeBcDhcp6CallBack (
 \r
   case Dhcp6RcvdAdvertise:\r
     Status = EFI_NOT_READY;\r
 \r
   case Dhcp6RcvdAdvertise:\r
     Status = EFI_NOT_READY;\r
+    if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
+      //\r
+      // Ignore the incoming packets which exceed the maximum length.\r
+      //\r
+      break;\r
+    }\r
     if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
       //\r
       // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
     if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
       //\r
       // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
@@ -1727,6 +1996,14 @@ PxeBcDhcp6CallBack (
     break;\r
 \r
   case Dhcp6SendRequest:\r
     break;\r
 \r
   case Dhcp6SendRequest:\r
+    if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
+      //\r
+      // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
+      //\r
+      Status = EFI_ABORTED;\r
+      break;\r
+    }\r
+    \r
     //\r
     // Store the request packet as seed packet for discover.\r
     //\r
     //\r
     // Store the request packet as seed packet for discover.\r
     //\r
@@ -1753,6 +2030,9 @@ PxeBcDhcp6CallBack (
       SelectAd   = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
       *NewPacket = AllocateZeroPool (SelectAd->Size);\r
       ASSERT (*NewPacket != NULL);\r
       SelectAd   = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
       *NewPacket = AllocateZeroPool (SelectAd->Size);\r
       ASSERT (*NewPacket != NULL);\r
+      if (*NewPacket == NULL) {\r
+        return EFI_ABORTED;\r
+      }\r
       CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
     }\r
     break;\r
       CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
     }\r
     break;\r
@@ -1763,7 +2043,10 @@ PxeBcDhcp6CallBack (
     // without verification.\r
     //\r
     ASSERT (Private->SelectIndex != 0);\r
     // without verification.\r
     //\r
     ASSERT (Private->SelectIndex != 0);\r
-    PxeBcCopyDhcp6Ack (Private, Packet, FALSE);\r
+    Status = PxeBcCopyDhcp6Ack (Private, Packet, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_ABORTED;\r
+    }\r
     break;\r
 \r
   default:\r
     break;\r
 \r
   default:\r