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