X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcBoot.c;h=d062a526077b270d35867d22012578e58445bd29;hp=540adee3113e412374d57342ea91b67401ba9070;hb=3f55418d5396629c4458061f283068b6c46895fc;hpb=a1c0d0fb2e0a31e493c302e04d7f9220e614218b
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
index 540adee311..d062a52607 100644
--- a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
@@ -1,15 +1,10 @@
/** @file
Boot functions implementation for UefiPxeBc Driver.
- Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -98,6 +93,17 @@ PxeBcSelectBootPrompt (
ASSERT (!Mode->UsingIpv6);
VendorOpt = &Cache->Dhcp4.VendorOpt;
+ //
+ // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,
+ // we must not consider a boot prompt or boot menu if all of the following hold:
+ // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set
+ // - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.
+ //
+ if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&
+ Cache->Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
+ return EFI_ABORTED;
+ }
+
if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {
return EFI_TIMEOUT;
}
@@ -133,7 +139,7 @@ PxeBcSelectBootPrompt (
Status = gBS->SetTimer (
TimeoutEvent,
TimerRelative,
- Timeout * TICKS_PER_SECOND
+ MultU64x32 (Timeout, TICKS_PER_SECOND)
);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
@@ -251,7 +257,7 @@ ON_EXIT:
@retval EFI_ABORTED User cancel operation.
@retval EFI_SUCCESS Select the boot menu success.
- @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
+ @retval EFI_NOT_READY Read the input key from the keyboard has not finish.
**/
EFI_STATUS
@@ -457,6 +463,8 @@ PxeBcDhcp4BootInfo (
EFI_STATUS Status;
PXEBC_DHCP4_PACKET_CACHE *Cache4;
UINT16 Value;
+ PXEBC_VENDOR_OPTION *VendorOpt;
+ PXEBC_BOOT_SVR_ENTRY *Entry;
PxeBc = &Private->PxeBc;
Mode = PxeBc->Mode;
@@ -474,17 +482,53 @@ PxeBcDhcp4BootInfo (
Cache4 = &Private->DhcpAck.Dhcp4;
}
+ if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
+ //
+ // This should never happen in a correctly configured DHCP / PXE
+ // environment. One misconfiguration that can cause it is two DHCP servers
+ // mistakenly running on the same network segment at the same time, and
+ // racing each other in answering DHCP requests. Thus, the DHCP packets
+ // that the edk2 PXE client considers "belonging together" may actually be
+ // entirely independent, coming from two (competing) DHCP servers.
+ //
+ // Try to deal with this gracefully. Note that this check is not
+ // comprehensive, as we don't try to identify all such errors.
+ //
+ return EFI_PROTOCOL_ERROR;
+ }
+
//
- // Parse the boot server Ipv4 address by next server address.
- // If this field isn't available, use option 54 instead.
+ // Parse the boot server address.
+ // If prompt/discover is disabled, get the first boot server from the boot servers list.
+ // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.
+ // If all these fields are not available, use option 54 instead.
//
- CopyMem (
- &Private->ServerIp,
- &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
- sizeof (EFI_IPv4_ADDRESS)
- );
-
+ VendorOpt = &Cache4->VendorOpt;
+ if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) {
+ Entry = VendorOpt->BootSvr;
+ if (VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry->IpCnt > 0) {
+ CopyMem (
+ &Private->ServerIp,
+ &Entry->IpAddr[0],
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ }
+ }
if (Private->ServerIp.Addr[0] == 0) {
+ //
+ // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.
+ // Try to use next server address field.
+ //
+ CopyMem (
+ &Private->ServerIp,
+ &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ }
+ if (Private->ServerIp.Addr[0] == 0) {
+ //
+ // Still failed , use the IP address from option 54.
+ //
CopyMem (
&Private->ServerIp,
Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
@@ -495,7 +539,6 @@ PxeBcDhcp4BootInfo (
//
// Parse the boot file name by option.
//
- ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;
if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
@@ -582,12 +625,35 @@ PxeBcDhcp6BootInfo (
Cache6 = &Private->DhcpAck.Dhcp6;
}
- ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
+ if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
+ //
+ // This should never happen in a correctly configured DHCP / PXE
+ // environment. One misconfiguration that can cause it is two DHCP servers
+ // mistakenly running on the same network segment at the same time, and
+ // racing each other in answering DHCP requests. Thus, the DHCP packets
+ // that the edk2 PXE client considers "belonging together" may actually be
+ // entirely independent, coming from two (competing) DHCP servers.
+ //
+ // Try to deal with this gracefully. Note that this check is not
+ // comprehensive, as we don't try to identify all such errors.
+ //
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Set the station address to IP layer.
+ //
+ Status = PxeBcSetIp6Address (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
//
// Parse (m)tftp server ip address and bootfile name.
//
Status = PxeBcExtractBootFileUrl (
+ Private,
&Private->BootFileName,
&Private->ServerIp.v6,
(CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
@@ -743,8 +809,8 @@ PxeBcExtractDiscoverInfo (
if (Info->IpCnt >= 1) {
*DiscoverInfo = AllocatePool (sizeof (*Info) + (Info->IpCnt - 1) * sizeof (**SrvList));
if (*DiscoverInfo == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
+ return EFI_OUT_OF_RESOURCES;
+ }
CopyMem (*DiscoverInfo, Info, sizeof (*Info));
Info = *DiscoverInfo;
}
@@ -905,7 +971,7 @@ PxeBcDiscoverBootFile (
&Mode->ProxyOffer.Dhcpv4,
&Mode->PxeReply.Dhcpv4,
Private->PxeReply.Dhcp4.Packet.Ack.Length
- );
+ );
}
Mode->ProxyOfferReceived = TRUE;
}
@@ -930,7 +996,7 @@ PxeBcDiscoverBootFile (
@param[in, out] Private Pointer to PxeBc private data.
@param[out] NewMakeCallback If TRUE, it is a new callback.
Otherwise, it is not new callback.
- @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succesfully.
+ @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed successfully.
@retval Others Failed to install PxeBaseCodeCallbackProtocol.
**/
@@ -948,7 +1014,7 @@ PxeBcInstallCallback (
//
PxeBc = &Private->PxeBc;
Status = gBS->HandleProtocol (
- Private->Controller,
+ Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,
&gEfiPxeBaseCodeCallbackProtocolGuid,
(VOID **) &Private->PxeBcCallback
);
@@ -964,7 +1030,7 @@ PxeBcInstallCallback (
// Install a default callback if user didn't offer one.
//
Status = gBS->InstallProtocolInterface (
- &Private->Controller,
+ Private->Mode.UsingIpv6 ? &Private->Ip6Nic->Controller : &Private->Ip4Nic->Controller,
&gEfiPxeBaseCodeCallbackProtocolGuid,
EFI_NATIVE_INTERFACE,
&Private->LoadFileCallback
@@ -1008,7 +1074,7 @@ PxeBcUninstallCallback (
PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
gBS->UninstallProtocolInterface (
- Private->Controller,
+ Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,
&gEfiPxeBaseCodeCallbackProtocolGuid,
&Private->LoadFileCallback
);
@@ -1185,7 +1251,7 @@ ON_EXIT:
PxeBcUninstallCallback(Private, NewMakeCallback);
if (Status == EFI_SUCCESS) {
- AsciiPrint ("\n Succeed to download NBP file.\n");
+ AsciiPrint ("\n NBP file downloaded successfully.\n");
return EFI_SUCCESS;
} else if (Status == EFI_BUFFER_TOO_SMALL && Buffer != NULL) {
AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
@@ -1196,7 +1262,7 @@ ON_EXIT:
} else if (Status == EFI_NO_MEDIA) {
AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
} else if (Status == EFI_NO_RESPONSE) {
- AsciiPrint ("\n PXE-E16: No offer received.\n");
+ AsciiPrint ("\n PXE-E16: No valid offer received.\n");
} else if (Status == EFI_TIMEOUT) {
AsciiPrint ("\n PXE-E18: Server response timeout.\n");
} else if (Status == EFI_ABORTED) {