X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcDhcp6.c;h=8003f314910ef015dfa032dbe61a94ffadbcbdf8;hp=c3ae23ec82f52d9059704456e62402c62b719b5d;hb=fa848a4048943251fc057fe8d6c5a82e01d2ffb6;hpb=eb2710af5bee8637741d92ed8d32df562941e6d9
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
index c3ae23ec82..8003f31491 100644
--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
@@ -1,7 +1,8 @@
/** @file
Functions implementation related with DHCPv6 for UefiPxeBc Driver.
- Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@@ -15,6 +16,12 @@
#include "PxeBcImpl.h"
+//
+// Well-known multi-cast address defined in section-24.1 of rfc-3315
+//
+// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
+//
+EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
/**
Parse out a DHCPv6 option by OptTag, and find the position in buffer.
@@ -232,8 +239,8 @@ PxeBcExtractBootFileUrl (
)
{
UINT16 PrefixLen;
- UINT8 *BootFileNamePtr;
- UINT8 *BootFileName;
+ CHAR8 *BootFileNamePtr;
+ CHAR8 *BootFileName;
UINT16 BootFileNameLen;
CHAR8 *TmpStr;
CHAR8 TmpChar;
@@ -314,7 +321,7 @@ PxeBcExtractBootFileUrl (
//
// Get the part of BOOTFILE_NAME string.
//
- BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1);
+ BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);
if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {
FreePool (TmpStr);
return EFI_INVALID_PARAMETER;
@@ -337,12 +344,12 @@ PxeBcExtractBootFileUrl (
//
// Extract boot file name from URL.
//
- BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen);
+ BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen);
if (BootFileName == NULL) {
FreePool (TmpStr);
return EFI_OUT_OF_RESOURCES;
}
- *FileName = BootFileName;
+ *FileName = (UINT8*) BootFileName;
//
// Decode percent-encoding in boot file name.
@@ -482,7 +489,7 @@ PxeBcParseDhcp6Packet (
}
//
- // The offer with assigned client address is a proxy offer.
+ // The offer with assigned client address is NOT a proxy offer.
// An ia_na option, embeded with valid ia_addr option and a status_code of success.
//
Option = Options[PXEBC_DHCP6_IDX_IA_NA];
@@ -658,7 +665,6 @@ PxeBcRequestBootService (
{
EFI_PXE_BASE_CODE_UDP_PORT SrcPort;
EFI_PXE_BASE_CODE_UDP_PORT DestPort;
- EFI_PXE_BASE_CODE_MODE *Mode;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;
UINTN DiscoverLen;
@@ -676,7 +682,6 @@ PxeBcRequestBootService (
UINT8 *Option;
PxeBc = &Private->PxeBc;
- Mode = PxeBc->Mode;
Request = Private->Dhcp6Request;
ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;
SrcPort = PXEBC_BS_DISCOVER_PORT;
@@ -788,8 +793,8 @@ PxeBcRequestBootService (
Status = PxeBc->UdpRead (
PxeBc,
- OpFlags,
- &Private->StationIp,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,
+ NULL,
&SrcPort,
&Private->ServerIp,
&DestPort,
@@ -844,19 +849,29 @@ PxeBcRetryDhcp6Binl (
Mode = Private->PxeBc.Mode;
Private->IsDoDiscover = FALSE;
Offer = &Private->OfferBuffer[Index].Dhcp6;
-
- ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
- //
- // Parse out the next server address from the last offer, and store it
- //
- Status = PxeBcExtractBootFileUrl (
- &Private->BootFileName,
- &Private->ServerIp.v6,
- (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
- NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
- );
- if (EFI_ERROR (Status)) {
- return Status;
+ if (Offer->OfferType == PxeOfferTypeDhcpBinl) {
+ //
+ // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
+ //
+ CopyMem (
+ &Private->ServerIp.v6,
+ &mAllDhcpRelayAndServersAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+ } else {
+ ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
+ //
+ // Parse out the next server address from the last offer, and store it
+ //
+ Status = PxeBcExtractBootFileUrl (
+ &Private->BootFileName,
+ &Private->ServerIp.v6,
+ (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
+ NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
}
//
@@ -1219,9 +1234,128 @@ PxeBcUnregisterIp6Address (
}
}
+/**
+ Check whether IP driver could route the message which will be sent to ServerIp address.
+
+ This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
+ route is found in IP6 route table, the address will be filed in GatewayAddr and return.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+ @param[in] TimeOutInSecond Timeout value in seconds.
+ @param[out] GatewayAddr Pointer to store the gateway IP address.
+
+ @retval EFI_SUCCESS Found a valid gateway address successfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval Other Unexpect error happened.
+
+**/
+EFI_STATUS
+PxeBcCheckRouteTable (
+ IN PXEBC_PRIVATE_DATA *Private,
+ IN UINTN TimeOutInSecond,
+ OUT EFI_IPv6_ADDRESS *GatewayAddr
+ )
+{
+ EFI_STATUS Status;
+ EFI_IP6_PROTOCOL *Ip6;
+ EFI_IP6_MODE_DATA Ip6ModeData;
+ UINTN Index;
+ EFI_EVENT TimeOutEvt;
+ UINTN RetryCount;
+ BOOLEAN GatewayIsFound;
+
+ ASSERT (GatewayAddr != NULL);
+ ASSERT (Private != NULL);
+
+ Ip6 = Private->Ip6;
+ GatewayIsFound = FALSE;
+ RetryCount = 0;
+ TimeOutEvt = NULL;
+ ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
+
+ while (TRUE) {
+ Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Find out the gateway address which can route the message which send to ServerIp.
+ //
+ for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
+ if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
+ IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
+ GatewayIsFound = TRUE;
+ break;
+ }
+ }
+
+ if (Ip6ModeData.AddressList != NULL) {
+ FreePool (Ip6ModeData.AddressList);
+ }
+ if (Ip6ModeData.GroupTable != NULL) {
+ FreePool (Ip6ModeData.GroupTable);
+ }
+ if (Ip6ModeData.RouteTable != NULL) {
+ FreePool (Ip6ModeData.RouteTable);
+ }
+ if (Ip6ModeData.NeighborCache != NULL) {
+ FreePool (Ip6ModeData.NeighborCache);
+ }
+ if (Ip6ModeData.PrefixTable != NULL) {
+ FreePool (Ip6ModeData.PrefixTable);
+ }
+ if (Ip6ModeData.IcmpTypeList != NULL) {
+ FreePool (Ip6ModeData.IcmpTypeList);
+ }
+
+ if (GatewayIsFound || RetryCount == TimeOutInSecond) {
+ break;
+ }
+
+ RetryCount++;
+
+ //
+ // Delay 1 second then recheck it again.
+ //
+ if (TimeOutEvt == NULL) {
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeOutEvt
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
+ Ip6->Poll (Ip6);
+ }
+ }
+
+ON_EXIT:
+ if (TimeOutEvt != NULL) {
+ gBS->CloseEvent (TimeOutEvt);
+ }
+
+ if (GatewayIsFound) {
+ Status = EFI_SUCCESS;
+ } else if (RetryCount == TimeOutInSecond) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
/**
- Register the ready address by Ip6Config protocol.
+ Register the ready station address and gateway by Ip6Config protocol.
@param[in] Private The pointer to PXEBC_PRIVATE_DATA.
@param[in] Address The pointer to the ready address.
@@ -1240,34 +1374,38 @@ PxeBcRegisterIp6Address (
EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
EFI_IP6_CONFIG_POLICY Policy;
EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
+ EFI_IPv6_ADDRESS GatewayAddr;
UINTN DataSize;
- EFI_EVENT TimeOutEvt;
EFI_EVENT MappedEvt;
EFI_STATUS Status;
+ BOOLEAN NoGateway;
+ EFI_IPv6_ADDRESS *Ip6Addr;
+ UINTN Index;
Status = EFI_SUCCESS;
- TimeOutEvt = NULL;
MappedEvt = NULL;
+ Ip6Addr = NULL;
DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
Ip6Cfg = Private->Ip6Cfg;
Ip6 = Private->Ip6;
+ NoGateway = FALSE;
ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));
- //
- // Get and store the current policy of IP6 driver.
- //
- Status = Ip6Cfg->GetData (
- Ip6Cfg,
- Ip6ConfigDataTypePolicy,
- &DataSize,
- &Private->Ip6Policy
- );
+ Status = Ip6->Configure (Ip6, &Private->Ip6CfgData);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
+ //
+ // Retrieve the gateway address from IP6 route table.
+ //
+ Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
+ if (EFI_ERROR (Status)) {
+ NoGateway = TRUE;
+ }
+
//
// There is no channel between IP6 and PXE driver about address setting,
// so it has to set the new address by Ip6ConfigProtocol manually.
@@ -1287,20 +1425,6 @@ PxeBcRegisterIp6Address (
goto ON_EXIT;
}
- //
- // Create a timer as setting address timeout event since DAD in IP6 driver.
- //
- Status = gBS->CreateEvent (
- EVT_TIMER,
- TPL_CALLBACK,
- NULL,
- NULL,
- &TimeOutEvt
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
//
// Create a notify event to set address flag when DAD if IP6 driver succeeded.
//
@@ -1315,6 +1439,7 @@ PxeBcRegisterIp6Address (
goto ON_EXIT;
}
+ Private->IsAddressOk = FALSE;
Status = Ip6Cfg->RegisterDataNotify (
Ip6Cfg,
Ip6ConfigDataTypeManualAddress,
@@ -1332,19 +1457,66 @@ PxeBcRegisterIp6Address (
);
if (EFI_ERROR(Status) && Status != EFI_NOT_READY) {
goto ON_EXIT;
- }
+ } else if (Status == EFI_NOT_READY) {
+ //
+ // Poll the network until the asynchronous process is finished.
+ //
+ while (!Private->IsAddressOk) {
+ Ip6->Poll (Ip6);
+ }
+ //
+ // Check whether the IP6 address setting is successed.
+ //
+ DataSize = 0;
+ Status = Ip6Cfg->GetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypeManualAddress,
+ &DataSize,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
- //
- // Start the 5 secondes timer to wait for setting address.
- //
- Status = EFI_NO_MAPPING;
- gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT);
+ Ip6Addr = AllocatePool (DataSize);
+ if (Ip6Addr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = Ip6Cfg->GetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypeManualAddress,
+ &DataSize,
+ (VOID*) Ip6Addr
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
- while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
- Ip6->Poll (Ip6);
- if (Private->IsAddressOk) {
- Status = EFI_SUCCESS;
- break;
+ for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) {
+ if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) {
+ break;
+ }
+ }
+ if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Set the default gateway address back if needed.
+ //
+ if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) {
+ Status = Ip6Cfg->SetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypeGateway,
+ sizeof (EFI_IPv6_ADDRESS),
+ &GatewayAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
}
}
@@ -1357,12 +1529,106 @@ ON_EXIT:
);
gBS->CloseEvent (MappedEvt);
}
- if (TimeOutEvt != NULL) {
- gBS->CloseEvent (TimeOutEvt);
+ if (Ip6Addr != NULL) {
+ FreePool (Ip6Addr);
+ }
+ return Status;
+}
+
+/**
+ Set the IP6 policy to Automatic.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Switch the IP policy succesfully.
+ @retval Others Unexpect error happened.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Policy (
+ IN PXEBC_PRIVATE_DATA *Private
+ )
+{
+ EFI_IP6_CONFIG_POLICY Policy;
+ EFI_STATUS Status;
+ EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
+ UINTN DataSize;
+
+ Ip6Cfg = Private->Ip6Cfg;
+ DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
+
+ //
+ // Get and store the current policy of IP6 driver.
+ //
+ Status = Ip6Cfg->GetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypePolicy,
+ &DataSize,
+ &Private->Ip6Policy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
}
+
+ if (Private->Ip6Policy == Ip6ConfigPolicyManual) {
+ Policy = Ip6ConfigPolicyAutomatic;
+ Status = Ip6Cfg->SetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypePolicy,
+ sizeof(EFI_IP6_CONFIG_POLICY),
+ &Policy
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no need to recover later.
+ //
+ Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
+ }
+ }
+
return Status;
}
+/**
+ This function will register the station IP address and flush IP instance to start using the new IP address.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS The new IP address has been configured successfully.
+ @retval Others Failed to configure the address.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Address (
+ IN PXEBC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_DHCP6_PROTOCOL *Dhcp6;
+
+ Dhcp6 = Private->Dhcp6;
+
+ CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS));
+ CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
+
+ Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
+ if (EFI_ERROR (Status)) {
+ Dhcp6->Stop (Dhcp6);
+ return Status;
+ }
+
+ Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
+ if (EFI_ERROR (Status)) {
+ PxeBcUnregisterIp6Address (Private);
+ Dhcp6->Stop (Dhcp6);
+ return Status;
+ }
+
+ AsciiPrint ("\n Station IP address is ");
+ PxeBcShowIp6Addr (&Private->StationIp.v6);
+
+ return EFI_SUCCESS;
+}
/**
EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
@@ -1544,7 +1810,6 @@ PxeBcDhcp6Discover (
UINT8 *RequestOpt;
UINT8 *DiscoverOpt;
UINTN ReadSize;
- UINT16 OpFlags;
UINT16 OpCode;
UINT16 OpLen;
UINT32 Xid;
@@ -1555,7 +1820,6 @@ PxeBcDhcp6Discover (
Request = Private->Dhcp6Request;
SrcPort = PXEBC_BS_DISCOVER_PORT;
DestPort = PXEBC_BS_DISCOVER_PORT;
- OpFlags = 0;
if (!UseBis && Layer != NULL) {
*Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
@@ -1599,7 +1863,7 @@ PxeBcDhcp6Discover (
Status = PxeBc->UdpWrite (
PxeBc,
- OpFlags,
+ 0,
&Private->ServerIp,
&DestPort,
NULL,
@@ -1626,10 +1890,18 @@ PxeBcDhcp6Discover (
}
ReadSize = (UINTN) Reply->Size;
+ //
+ // Start Udp6Read instance
+ //
+ Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
Status = PxeBc->UdpRead (
PxeBc,
- OpFlags,
- &Private->StationIp,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,
+ NULL,
&SrcPort,
&Private->ServerIp,
&DestPort,
@@ -1638,6 +1910,10 @@ PxeBcDhcp6Discover (
&ReadSize,
(VOID *) &Reply->Dhcp6
);
+ //
+ // Stop Udp6Read instance
+ //
+ Private->Udp6Read->Configure (Private->Udp6Read, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1670,9 +1946,17 @@ PxeBcDhcp6Sarr (
UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];
UINT32 OptCount;
EFI_STATUS Status;
+ EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
+ EFI_STATUS TimerStatus;
+ EFI_EVENT Timer;
+ UINT64 GetMappingTimeOut;
+ UINTN DataSize;
+ EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
Status = EFI_SUCCESS;
PxeMode = Private->PxeBc.Mode;
+ Ip6Cfg = Private->Ip6Cfg;
+ Timer = NULL;
//
// Build option list for the request packet.
@@ -1695,7 +1979,7 @@ PxeBcDhcp6Sarr (
Config.IaInfoEvent = NULL;
Config.RapidCommit = FALSE;
Config.ReconfigureAccept = FALSE;
- Config.IaDescriptor.IaId = 1;
+ Config.IaDescriptor.IaId = Private->IaId;
Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
Config.SolicitRetransmission = Retransmit;
Retransmit->Irt = 4;
@@ -1707,8 +1991,8 @@ PxeBcDhcp6Sarr (
// Configure the DHCPv6 instance for PXE boot.
//
Status = Dhcp6->Configure (Dhcp6, &Config);
+ FreePool (Retransmit);
if (EFI_ERROR (Status)) {
- FreePool (Retransmit);
return Status;
}
@@ -1726,6 +2010,52 @@ PxeBcDhcp6Sarr (
// Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
//
Status = Dhcp6->Start (Dhcp6);
+ if (Status == EFI_NO_MAPPING) {
+ //
+ // IP6 Linklocal address is not available for use, so stop current Dhcp process
+ // and wait for duplicate address detection to finish.
+ //
+ Dhcp6->Stop (Dhcp6);
+
+ //
+ // Get Duplicate Address Detection Transmits count.
+ //
+ DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
+ Status = Ip6Cfg->GetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypeDupAddrDetectTransmits,
+ &DataSize,
+ &DadXmits
+ );
+ if (EFI_ERROR (Status)) {
+ Dhcp6->Configure (Dhcp6, NULL);
+ return Status;
+ }
+
+ Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
+ if (EFI_ERROR (Status)) {
+ Dhcp6->Configure (Dhcp6, NULL);
+ return Status;
+ }
+
+ GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;
+ Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Timer);
+ Dhcp6->Configure (Dhcp6, NULL);
+ return Status;
+ }
+
+ do {
+
+ TimerStatus = gBS->CheckEvent (Timer);
+ if (!EFI_ERROR (TimerStatus)) {
+ Status = Dhcp6->Start (Dhcp6);
+ }
+ } while (TimerStatus == EFI_NOT_READY);
+
+ gBS->CloseEvent (Timer);
+ }
if (EFI_ERROR (Status)) {
if (Status == EFI_ICMP_ERROR) {
PxeMode->IcmpErrorReceived = TRUE;
@@ -1743,37 +2073,29 @@ PxeBcDhcp6Sarr (
return Status;
}
- ASSERT (Mode.Ia->State == Dhcp6Bound);
- CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
- CopyMem (&PxeMode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
-
- Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
- if (EFI_ERROR (Status)) {
- Dhcp6->Stop (Dhcp6);
- return Status;
+ ASSERT ((Mode.Ia != NULL) && (Mode.Ia->State == Dhcp6Bound));
+ //
+ // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
+ // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
+ // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
+ // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
+ // to find a valid router address.
+ //
+ CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
+ if (Mode.ClientId != NULL) {
+ FreePool (Mode.ClientId);
}
-
- Status = PxeBcFlushStaionIp (Private, &Private->StationIp, NULL);
- if (EFI_ERROR (Status)) {
- PxeBcUnregisterIp6Address (Private);
- Dhcp6->Stop (Dhcp6);
- return Status;
+ if (Mode.Ia != NULL) {
+ FreePool (Mode.Ia);
}
-
//
// Check the selected offer whether BINL retry is needed.
//
Status = PxeBcHandleDhcp6Offer (Private);
if (EFI_ERROR (Status)) {
- PxeBcUnregisterIp6Address (Private);
Dhcp6->Stop (Dhcp6);
return Status;
}
-
- AsciiPrint ("\n Station IP address is ");
-
- PxeBcShowIp6Addr (&Private->StationIp.v6);
-
+
return EFI_SUCCESS;
}
-