]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
NetworkPkg/UefiPxeBcDxe: handle competing DHCP servers (more) gracefully
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcBoot.c
index 253115308e8159d9f38ef773148b4acace8d7f57..d062a526077b270d35867d22012578e58445bd29 100644 (file)
@@ -1,15 +1,10 @@
 /** @file\r
   Boot functions implementation for UefiPxeBc Driver.\r
 \r
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php.\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -101,14 +96,14 @@ PxeBcSelectBootPrompt (
   //\r
   // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,\r
   // we must not consider a boot prompt or boot menu if all of the following hold:\r
-  //   - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set  \r
+  //   - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set\r
   //   - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.\r
   //\r
   if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&\r
       Cache->Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
     return EFI_ABORTED;\r
   }\r
-  \r
+\r
   if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
     return EFI_TIMEOUT;\r
   }\r
@@ -144,7 +139,7 @@ PxeBcSelectBootPrompt (
   Status = gBS->SetTimer (\r
                   TimeoutEvent,\r
                   TimerRelative,\r
-                  Timeout * TICKS_PER_SECOND\r
+                  MultU64x32 (Timeout, TICKS_PER_SECOND)\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
@@ -262,7 +257,7 @@ ON_EXIT:
 \r
   @retval EFI_ABORTED     User cancel operation.\r
   @retval EFI_SUCCESS     Select the boot menu success.\r
-  @retval EFI_NOT_READY   Read the input key from the keybroad has not finish.\r
+  @retval EFI_NOT_READY   Read the input key from the keyboard has not finish.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -470,7 +465,7 @@ PxeBcDhcp4BootInfo (
   UINT16                      Value;\r
   PXEBC_VENDOR_OPTION         *VendorOpt;\r
   PXEBC_BOOT_SVR_ENTRY        *Entry;\r
-  \r
+\r
   PxeBc       = &Private->PxeBc;\r
   Mode        = PxeBc->Mode;\r
   Status      = EFI_SUCCESS;\r
@@ -487,7 +482,20 @@ PxeBcDhcp4BootInfo (
     Cache4 = &Private->DhcpAck.Dhcp4;\r
   }\r
 \r
-  ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
+  if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
+    //\r
+    // This should never happen in a correctly configured DHCP / PXE\r
+    // environment. One misconfiguration that can cause it is two DHCP servers\r
+    // mistakenly running on the same network segment at the same time, and\r
+    // racing each other in answering DHCP requests. Thus, the DHCP packets\r
+    // that the edk2 PXE client considers "belonging together" may actually be\r
+    // entirely independent, coming from two (competing) DHCP servers.\r
+    //\r
+    // Try to deal with this gracefully. Note that this check is not\r
+    // comprehensive, as we don't try to identify all such errors.\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
 \r
   //\r
   // Parse the boot server address.\r
@@ -617,12 +625,35 @@ PxeBcDhcp6BootInfo (
     Cache6 = &Private->DhcpAck.Dhcp6;\r
   }\r
 \r
-  ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
+  if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
+    //\r
+    // This should never happen in a correctly configured DHCP / PXE\r
+    // environment. One misconfiguration that can cause it is two DHCP servers\r
+    // mistakenly running on the same network segment at the same time, and\r
+    // racing each other in answering DHCP requests. Thus, the DHCP packets\r
+    // that the edk2 PXE client considers "belonging together" may actually be\r
+    // entirely independent, coming from two (competing) DHCP servers.\r
+    //\r
+    // Try to deal with this gracefully. Note that this check is not\r
+    // comprehensive, as we don't try to identify all such errors.\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  //\r
+  // Set the station address to IP layer.\r
+  //\r
+  Status = PxeBcSetIp6Address (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
 \r
   //\r
   // Parse (m)tftp server ip address and bootfile name.\r
   //\r
   Status = PxeBcExtractBootFileUrl (\r
+             Private,\r
              &Private->BootFileName,\r
              &Private->ServerIp.v6,\r
              (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
@@ -632,14 +663,6 @@ PxeBcDhcp6BootInfo (
     return Status;\r
   }\r
 \r
-  //\r
-  // Set the station address to IP layer.\r
-  //\r
-  Status = PxeBcSetIp6Address (Private);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-  \r
   //\r
   // Parse the value of boot file size.\r
   //\r
@@ -786,8 +809,8 @@ PxeBcExtractDiscoverInfo (
       if (Info->IpCnt >= 1) {\r
         *DiscoverInfo = AllocatePool (sizeof (*Info) + (Info->IpCnt - 1) * sizeof (**SrvList));\r
         if (*DiscoverInfo == NULL) {\r
-          return EFI_OUT_OF_RESOURCES;       \r
-        }     \r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
         CopyMem (*DiscoverInfo, Info, sizeof (*Info));\r
         Info = *DiscoverInfo;\r
       }\r
@@ -948,7 +971,7 @@ PxeBcDiscoverBootFile (
           &Mode->ProxyOffer.Dhcpv4,\r
           &Mode->PxeReply.Dhcpv4,\r
           Private->PxeReply.Dhcp4.Packet.Ack.Length\r
-          );      \r
+          );\r
       }\r
       Mode->ProxyOfferReceived = TRUE;\r
     }\r
@@ -973,7 +996,7 @@ PxeBcDiscoverBootFile (
   @param[in, out] Private           Pointer to PxeBc private data.\r
   @param[out]     NewMakeCallback   If TRUE, it is a new callback.\r
                                     Otherwise, it is not new callback.\r
-  @retval EFI_SUCCESS          PxeBaseCodeCallbackProtocol installed succesfully.\r
+  @retval EFI_SUCCESS          PxeBaseCodeCallbackProtocol installed successfully.\r
   @retval Others               Failed to install PxeBaseCodeCallbackProtocol.\r
 \r
 **/\r
@@ -991,7 +1014,7 @@ PxeBcInstallCallback (
   //\r
   PxeBc  = &Private->PxeBc;\r
   Status = gBS->HandleProtocol (\r
-                  Private->Controller,\r
+                  Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,\r
                   &gEfiPxeBaseCodeCallbackProtocolGuid,\r
                   (VOID **) &Private->PxeBcCallback\r
                   );\r
@@ -1007,7 +1030,7 @@ PxeBcInstallCallback (
     // Install a default callback if user didn't offer one.\r
     //\r
     Status = gBS->InstallProtocolInterface (\r
-                    &Private->Controller,\r
+                    Private->Mode.UsingIpv6 ? &Private->Ip6Nic->Controller : &Private->Ip4Nic->Controller,\r
                     &gEfiPxeBaseCodeCallbackProtocolGuid,\r
                     EFI_NATIVE_INTERFACE,\r
                     &Private->LoadFileCallback\r
@@ -1051,7 +1074,7 @@ PxeBcUninstallCallback (
     PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);\r
 \r
     gBS->UninstallProtocolInterface (\r
-          Private->Controller,\r
+          Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,\r
           &gEfiPxeBaseCodeCallbackProtocolGuid,\r
           &Private->LoadFileCallback\r
           );\r
@@ -1228,7 +1251,7 @@ ON_EXIT:
   PxeBcUninstallCallback(Private, NewMakeCallback);\r
 \r
   if (Status == EFI_SUCCESS) {\r
-    AsciiPrint ("\n  Succeed to download NBP file.\n");\r
+    AsciiPrint ("\n  NBP file downloaded successfully.\n");\r
     return EFI_SUCCESS;\r
   } else if (Status == EFI_BUFFER_TOO_SMALL && Buffer != NULL) {\r
     AsciiPrint ("\n  PXE-E05: Buffer size is smaller than the requested file.\n");\r
@@ -1239,7 +1262,7 @@ ON_EXIT:
   } else if (Status == EFI_NO_MEDIA) {\r
     AsciiPrint ("\n  PXE-E12: Could not detect network connection.\n");\r
   } else if (Status == EFI_NO_RESPONSE) {\r
-    AsciiPrint ("\n  PXE-E16: No offer received.\n");\r
+    AsciiPrint ("\n  PXE-E16: No valid offer received.\n");\r
   } else if (Status == EFI_TIMEOUT) {\r
     AsciiPrint ("\n  PXE-E18: Server response timeout.\n");\r
   } else if (Status == EFI_ABORTED) {\r