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) {