Skip to content

Commit 87366ac

Browse files
samtsai0121makubacki
authored andcommitted
[CHERRY-PICK] NetworkPkg/HttpBootDxe: Wait for IPv6 DAD before issuing DHCPv6 requests
Align HTTP Boot behavior with PXE by inserting a delay to wait for IPv6 Duplicate Address Detection (DAD) to complete before issuing DHCPv6 requests. This avoids EFI_NO_MAPPING errors caused by early DHCP attempts before a valid IPv6 address is ready. Problem: On some platforms, HTTP boot over IPv6 fails with EFI_NO_MAPPING during initial DHCPv6 attempts. The failure is due to the system trying to send Solicit messages before IPv6 DAD finishes, resulting in no usable IP address at that time. Solution: Insert a retry mechanism to poll DAD completion when the initial call to Dhcp6->Start() fails with EFI_NO_MAPPING. This behavior mirrors PXE's handling, where it waits for a valid IPv6 address to be assigned before retrying the DHCPv6 flow. Signed-off-by: Sam Tsai [Wiwynn] <[email protected]> (cherry picked from commit 11f1d28)
1 parent 7afb1e3 commit 87366ac

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

NetworkPkg/HttpBootDxe/HttpBootDhcp6.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,82 @@ HttpBootSetIp6Address (
930930
return Status;
931931
}
932932

933+
/**
934+
Retry DHCPv6 when EFI_NO_MAPPING is returned, by waiting for Duplicate Address
935+
Detection (DAD) to complete and restarting the DHCPv6 process.
936+
937+
This function stops the current DHCP6 session and waits for DAD to complete
938+
based on the value returned by Ip6Config->GetData(), then retries Dhcp6->Start().
939+
940+
@param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.
941+
@param[in] Ip6Cfg The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
942+
943+
@retval EFI_SUCCESS DHCPv6 process restarted successfully after DAD.
944+
@retval EFI_DEVICE_ERROR Failed during DAD timer wait or DHCP restart.
945+
@retval EFI_OUT_OF_RESOURCES Failed to allocate timer resources.
946+
@retval Others Underlying protocol errors.
947+
948+
**/
949+
EFI_STATUS
950+
HandleDhcp6NoMappingRetry (
951+
IN EFI_DHCP6_PROTOCOL *Dhcp6,
952+
IN EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg
953+
)
954+
{
955+
EFI_STATUS Status;
956+
EFI_STATUS TimerStatus;
957+
EFI_EVENT Timer = NULL;
958+
UINT64 GetMappingTimeOut;
959+
UINTN DataSize;
960+
EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
961+
962+
//
963+
// IP6 Linklocal address is not available for use, so stop current Dhcp process
964+
// and wait for duplicate address detection to finish.
965+
//
966+
Dhcp6->Stop (Dhcp6);
967+
968+
//
969+
// Get Duplicate Address Detection Transmits count.
970+
//
971+
DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
972+
Status = Ip6Cfg->GetData (
973+
Ip6Cfg,
974+
Ip6ConfigDataTypeDupAddrDetectTransmits,
975+
&DataSize,
976+
&DadXmits
977+
);
978+
if (EFI_ERROR (Status)) {
979+
Dhcp6->Configure (Dhcp6, NULL);
980+
return Status;
981+
}
982+
983+
Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
984+
if (EFI_ERROR (Status)) {
985+
Dhcp6->Configure (Dhcp6, NULL);
986+
return Status;
987+
}
988+
989+
GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + HTTP_BOOT_DAD_ADDITIONAL_DELAY;
990+
Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
991+
if (EFI_ERROR (Status)) {
992+
gBS->CloseEvent (Timer);
993+
Dhcp6->Configure (Dhcp6, NULL);
994+
return Status;
995+
}
996+
997+
do {
998+
TimerStatus = gBS->CheckEvent (Timer);
999+
if (!EFI_ERROR (TimerStatus)) {
1000+
Status = Dhcp6->Start (Dhcp6);
1001+
}
1002+
} while (TimerStatus == EFI_NOT_READY);
1003+
1004+
gBS->CloseEvent (Timer);
1005+
1006+
return Status;
1007+
}
1008+
9331009
/**
9341010
Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
9351011
@@ -953,10 +1029,14 @@ HttpBootDhcp6Sarr (
9531029
UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];
9541030
EFI_STATUS Status;
9551031
UINT32 Random;
1032+
EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
9561033

9571034
Dhcp6 = Private->Dhcp6;
9581035
ASSERT (Dhcp6 != NULL);
9591036

1037+
ASSERT (Private->UsingIpv6);
1038+
Ip6Cfg = Private->Ip6Config;
1039+
9601040
//
9611041
// Build options list for the request packet.
9621042
//
@@ -1013,6 +1093,10 @@ HttpBootDhcp6Sarr (
10131093
// Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
10141094
//
10151095
Status = Dhcp6->Start (Dhcp6);
1096+
if (Status == EFI_NO_MAPPING) {
1097+
Status = HandleDhcp6NoMappingRetry (Dhcp6, Ip6Cfg);
1098+
}
1099+
10161100
if (EFI_ERROR (Status)) {
10171101
goto ON_EXIT;
10181102
}

NetworkPkg/HttpBootDxe/HttpBootDhcp6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
1616
#define HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT 10
1717
#define HTTP_BOOT_DEFAULT_HOPLIMIT 64
1818
#define HTTP_BOOT_DEFAULT_LIFETIME 50000
19+
#define HTTP_BOOT_DAD_ADDITIONAL_DELAY 30000000 // 3 seconds
1920

2021
#define HTTP_BOOT_DHCP6_ENTERPRISE_NUM 343 // TODO: IANA TBD: temporarily using Intel's
2122
#define HTTP_BOOT_DHCP6_MAX_BOOT_FILE_SIZE 65535 // It's a limitation of bit length, 65535*512 bytes.

0 commit comments

Comments
 (0)