/** @file\r
Boot functions implementation for UefiPxeBc Driver.\r
\r
- Copyright (c) 2009 - 2011, 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
OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;\r
\r
//\r
- // Only ProxyPxe10 offer needs boot prompt.\r
+ // Only DhcpPxe10 and ProxyPxe10 offer needs boot prompt.\r
//\r
- if (OfferType != PxeOfferTypeProxyPxe10) {\r
+ if (OfferType != PxeOfferTypeProxyPxe10 && OfferType != PxeOfferTypeDhcpPxe10) {\r
return EFI_NOT_FOUND;\r
}\r
\r
ASSERT (!Mode->UsingIpv6);\r
\r
VendorOpt = &Cache->Dhcp4.VendorOpt;\r
+ //\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
+ // - 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
if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
- return EFI_SUCCESS;\r
+ return EFI_TIMEOUT;\r
}\r
\r
Timeout = VendorOpt->MenuPrompt->Timeout;\r
// The valid scope of Timeout refers to PXE2.1 spec.\r
//\r
if (Timeout == 0) {\r
- return EFI_SUCCESS;\r
+ return EFI_TIMEOUT;\r
}\r
if (Timeout == 255) {\r
- return EFI_TIMEOUT;\r
+ return EFI_SUCCESS;\r
}\r
\r
//\r
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
gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
AsciiPrint ("(%d) ", Timeout--);\r
\r
+ Status = EFI_TIMEOUT;\r
while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
}\r
//\r
// Parse the input key by user.\r
+ // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.\r
//\r
if (InputKey.ScanCode == 0) {\r
\r
case CTRL ('m'):\r
case 'm':\r
case 'M':\r
- Status = EFI_TIMEOUT;\r
+ Status = EFI_SUCCESS;\r
break;\r
\r
default:\r
switch (InputKey.ScanCode) {\r
\r
case SCAN_F8:\r
- Status = EFI_TIMEOUT;\r
+ Status = EFI_SUCCESS;\r
break;\r
\r
case SCAN_ESC:\r
PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MENU_MAX_NUM];\r
\r
Finish = FALSE;\r
- Select = 1;\r
+ Select = 0;\r
Index = 0;\r
*Type = 0;\r
Mode = Private->PxeBc.Mode;\r
OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;\r
\r
//\r
- // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.\r
+ // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.\r
//\r
ASSERT (!Mode->UsingIpv6);\r
- ASSERT (OfferType == PxeOfferTypeProxyPxe10);\r
+ ASSERT (OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeDhcpPxe10);\r
\r
VendorOpt = &Cache->Dhcp4.VendorOpt;\r
if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
gBS->Stall (10 * TICKS_PER_MS);\r
}\r
\r
- if (InputKey.ScanCode != 0) {\r
+ if (InputKey.ScanCode == 0) {\r
switch (InputKey.UnicodeChar) {\r
case CTRL ('c'):\r
InputKey.ScanCode = SCAN_ESC;\r
EFI_STATUS Status;\r
PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
UINT16 Value;\r
+ PXEBC_VENDOR_OPTION *VendorOpt;\r
+ PXEBC_BOOT_SVR_ENTRY *Entry;\r
\r
PxeBc = &Private->PxeBc;\r
Mode = PxeBc->Mode;\r
Cache4 = &Private->DhcpAck.Dhcp4;\r
}\r
\r
+ ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
+\r
//\r
- // Parse the boot server Ipv4 address by next server address.\r
- // If this field isn't available, use option 54 instead.\r
+ // Parse the boot server address.\r
+ // If prompt/discover is disabled, get the first boot server from the boot servers list.\r
+ // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.\r
+ // If all these fields are not available, use option 54 instead.\r
//\r
- CopyMem (\r
- &Private->ServerIp,\r
- &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,\r
- sizeof (EFI_IPv4_ADDRESS)\r
- );\r
-\r
+ VendorOpt = &Cache4->VendorOpt;\r
+ if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) {\r
+ Entry = VendorOpt->BootSvr;\r
+ if (VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry->IpCnt > 0) {\r
+ CopyMem (\r
+ &Private->ServerIp,\r
+ &Entry->IpAddr[0],\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+ }\r
+ }\r
if (Private->ServerIp.Addr[0] == 0) {\r
+ //\r
+ // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.\r
+ // Try to use next server address field.\r
+ //\r
+ CopyMem (\r
+ &Private->ServerIp,\r
+ &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+ }\r
+ if (Private->ServerIp.Addr[0] == 0) {\r
+ //\r
+ // Still failed , use the IP address from option 54.\r
+ //\r
CopyMem (\r
&Private->ServerIp,\r
Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
//\r
// Parse the boot file name by option.\r
//\r
- ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;\r
\r
if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {\r
\r
ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\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
\r
@param[in] Private Pointer to PxeBc private data.\r
@param[in] Type The type of bootstrap to perform.\r
- @param[in, out] Info Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.\r
+ @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.\r
@param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.\r
@param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.\r
\r
PxeBcExtractDiscoverInfo (\r
IN PXEBC_PRIVATE_DATA *Private,\r
IN UINT16 Type,\r
- IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO *Info,\r
+ IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO **DiscoverInfo,\r
OUT PXEBC_BOOT_SVR_ENTRY **BootEntry,\r
OUT EFI_PXE_BASE_CODE_SRVLIST **SrvList\r
)\r
PXEBC_VENDOR_OPTION *VendorOpt;\r
PXEBC_BOOT_SVR_ENTRY *Entry;\r
BOOLEAN IsFound;\r
+ EFI_PXE_BASE_CODE_DISCOVER_INFO *Info;\r
+ UINT16 Index;\r
\r
Mode = Private->PxeBc.Mode;\r
+ Info = *DiscoverInfo;\r
\r
if (Mode->UsingIpv6) {\r
Info->IpCnt = 1;\r
Info->UseMCast = (BOOLEAN) !IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
Info->UseBCast = (BOOLEAN) !IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
Info->MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);\r
- Info->UseUCast = Info->MustUseList;\r
+ Info->UseUCast = (BOOLEAN) IS_VALID_BOOT_SERVERS (VendorOpt->BitMap);\r
\r
if (Info->UseMCast) {\r
//\r
\r
Info->IpCnt = 0;\r
\r
- if (Info->MustUseList) {\r
+ if (Info->UseUCast) {\r
Entry = VendorOpt->BootSvr;\r
\r
while (((UINT8) (Entry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {\r
}\r
\r
Info->IpCnt = Entry->IpCnt;\r
+ 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
+ CopyMem (*DiscoverInfo, Info, sizeof (*Info));\r
+ Info = *DiscoverInfo;\r
+ }\r
+\r
+ for (Index = 0; Index < Info->IpCnt; Index++) {\r
+ CopyMem (&Info->SrvList[Index].IpAddr, &Entry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
+ Info->SrvList[Index].AcceptAnyResponse = !Info->MustUseList;\r
+ Info->SrvList[Index].Type = NTOHS (Entry->Type);\r
+ }\r
}\r
\r
*BootEntry = Entry;\r
+ *SrvList = Info->SrvList;\r
}\r
\r
return EFI_SUCCESS;\r
//\r
// Choose by user's input.\r
//\r
- Status = PxeBcSelectBootMenu (Private, &Type, TRUE);\r
+ Status = PxeBcSelectBootMenu (Private, &Type, FALSE);\r
} else if (Status == EFI_TIMEOUT) {\r
//\r
// Choose by default item.\r
//\r
- Status = PxeBcSelectBootMenu (Private, &Type, FALSE);\r
+ Status = PxeBcSelectBootMenu (Private, &Type, TRUE);\r
}\r
\r
if (!EFI_ERROR (Status)) {\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
+ if (Mode->PxeReplyReceived && !Mode->ProxyOfferReceived) {\r
+ //\r
+ // Some network boot loader only search the packet in Mode.ProxyOffer to get its server\r
+ // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.\r
+ //\r
+ if (Mode->UsingIpv6) {\r
+ CopyMem (\r
+ &Mode->ProxyOffer.Dhcpv6,\r
+ &Mode->PxeReply.Dhcpv6,\r
+ Private->PxeReply.Dhcp6.Packet.Ack.Length\r
+ );\r
+ } else {\r
+ CopyMem (\r
+ &Mode->ProxyOffer.Dhcpv4,\r
+ &Mode->PxeReply.Dhcpv4,\r
+ Private->PxeReply.Dhcp4.Packet.Ack.Length\r
+ );\r
+ }\r
+ Mode->ProxyOfferReceived = TRUE;\r
+ }\r
}\r
\r
//\r
//\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
// 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
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
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
} 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
AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");\r
} else if (Status == EFI_TFTP_ERROR) {\r
AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ AsciiPrint ("\n PXE-E53: No boot filename received.\n");\r
} else if (Status != EFI_BUFFER_TOO_SMALL) {\r
AsciiPrint ("\n PXE-E99: Unexpected network error.\n");\r
}\r