X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcDhcp6.c;h=c93bad94342c28267f102f5c938090c97c26d580;hb=393a3169c2a777e3ed899c85f7827258a13f0755;hp=23ec9e7fc9e42e5409e596c602fb093dd2c94b5d;hpb=129b8b096fa2f87a4b24f31c004dea7bfe7872dd;p=mirror_edk2.git
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
index 23ec9e7fc9..c93bad9434 100644
--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
@@ -1,7 +1,7 @@
/** @file
Functions implementation related with DHCPv6 for UefiPxeBc Driver.
- Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, 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 +15,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,13 +238,14 @@ PxeBcExtractBootFileUrl (
)
{
UINT16 PrefixLen;
- UINT8 *BootFileNamePtr;
- UINT8 *BootFileName;
+ CHAR8 *BootFileNamePtr;
+ CHAR8 *BootFileName;
UINT16 BootFileNameLen;
CHAR8 *TmpStr;
CHAR8 TmpChar;
CHAR8 *ServerAddressOption;
CHAR8 *ServerAddress;
+ CHAR8 *ModeStr;
EFI_STATUS Status;
//
@@ -313,7 +320,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;
@@ -322,15 +329,26 @@ PxeBcExtractBootFileUrl (
++BootFileNamePtr;
BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);
if (BootFileNameLen != 0 || FileName != NULL) {
+ //
+ // Remove trailing mode=octet if present and ignore. All other modes are
+ // invalid for netboot6, so reject them.
+ //
+ ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet");
+ if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') {
+ *ModeStr = '\0';
+ } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
//
// 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.
@@ -339,7 +357,7 @@ PxeBcExtractBootFileUrl (
if (*BootFileNamePtr == '%') {
TmpChar = *(BootFileNamePtr+ 3);
*(BootFileNamePtr+ 3) = '\0';
- *BootFileName = (UINT8) AsciiStrHexToUintn (BootFileNamePtr + 1);
+ *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1));
BootFileName++;
*(BootFileNamePtr+ 3) = TmpChar;
BootFileNamePtr += 3;
@@ -776,7 +794,7 @@ PxeBcRequestBootService (
Status = PxeBc->UdpRead (
PxeBc,
- OpFlags,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
&Private->StationIp,
&SrcPort,
&Private->ServerIp,
@@ -832,19 +850,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;
+ }
}
//
@@ -1232,6 +1260,8 @@ PxeBcRegisterIp6Address (
EFI_EVENT TimeOutEvt;
EFI_EVENT MappedEvt;
EFI_STATUS Status;
+ UINT64 DadTriggerTime;
+ EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
Status = EFI_SUCCESS;
TimeOutEvt = NULL;
@@ -1275,6 +1305,20 @@ PxeBcRegisterIp6Address (
goto ON_EXIT;
}
+ //
+ // 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)) {
+ goto ON_EXIT;
+ }
+
//
// Create a timer as setting address timeout event since DAD in IP6 driver.
//
@@ -1326,7 +1370,8 @@ PxeBcRegisterIp6Address (
// Start the 5 secondes timer to wait for setting address.
//
Status = EFI_NO_MAPPING;
- gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT);
+ DadTriggerTime = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;
+ gBS->SetTimer (TimeOutEvt, TimerRelative, DadTriggerTime);
while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
Ip6->Poll (Ip6);
@@ -1614,6 +1659,14 @@ 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,
@@ -1626,6 +1679,10 @@ PxeBcDhcp6Discover (
&ReadSize,
(VOID *) &Reply->Dhcp6
);
+ //
+ // Stop Udp6Read instance
+ //
+ Private->Udp6Read->Configure (Private->Udp6Read, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1658,9 +1715,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.
@@ -1683,7 +1748,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;
@@ -1695,8 +1760,8 @@ PxeBcDhcp6Sarr (
// Configure the DHCPv6 instance for PXE boot.
//
Status = Dhcp6->Configure (Dhcp6, &Config);
+ FreePool (Retransmit);
if (EFI_ERROR (Status)) {
- FreePool (Retransmit);
return Status;
}
@@ -1714,6 +1779,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;
@@ -1741,7 +1852,7 @@ PxeBcDhcp6Sarr (
return Status;
}
- Status = PxeBcFlushStaionIp (Private, &Private->StationIp, NULL);
+ Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
if (EFI_ERROR (Status)) {
PxeBcUnregisterIp6Address (Private);
Dhcp6->Stop (Dhcp6);