X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcDhcp6.c;h=6a08e9a2de68a56cebf1c71174ec6364af4119bc;hb=471342bbefaac1c21fe7fa4e80949b552b12fbdd;hp=6ad5f5f1ac9fd5eb318a3fcd55e597d13e92dbd7;hpb=bf9f7cea98616e7b780946e61068bd345e454915;p=mirror_edk2.git diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index 6ad5f5f1ac..6a08e9a2de 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -2,7 +2,7 @@ Functions implementation related with DHCPv6 for UefiPxeBc Driver. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ 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 @@ -92,18 +92,19 @@ PxeBcBuildDhcp6Options ( // // Append client option request option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ORO); - OptList[Index]->OpLen = HTONS (4); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO); + OptList[Index]->OpLen = HTONS (6); OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data; - OptEnt.Oro->OpCode[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL); - OptEnt.Oro->OpCode[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM); + OptEnt.Oro->OpCode[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL); + OptEnt.Oro->OpCode[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM); + OptEnt.Oro->OpCode[2] = HTONS(DHCP6_OPT_DNS_SERVERS); Index++; OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); // // Append client network device interface option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_UNDI); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI); OptList[Index]->OpLen = HTONS ((UINT16)3); OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data; @@ -123,7 +124,7 @@ PxeBcBuildDhcp6Options ( // // Append client system architecture option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ARCH); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH); OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH)); OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data; Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); @@ -134,7 +135,7 @@ PxeBcBuildDhcp6Options ( // // Append vendor class option to store the PXE class identifier. // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS); OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS)); OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data; OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM); @@ -216,10 +217,173 @@ PxeBcFreeBootFileOption ( } } +/** + Retrieve the boot server address using the EFI_DNS6_PROTOCOL. + + @param[in] Private Pointer to PxeBc private data. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +PxeBcDns6 ( + IN PXEBC_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + EFI_STATUS Status; + EFI_DNS6_PROTOCOL *Dns6; + EFI_DNS6_CONFIG_DATA Dns6ConfigData; + EFI_DNS6_COMPLETION_TOKEN Token; + EFI_HANDLE Dns6Handle; + EFI_IPv6_ADDRESS *DnsServerList; + BOOLEAN IsDone; + + Dns6 = NULL; + Dns6Handle = NULL; + DnsServerList = Private->DnsServer; + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); + + // + // Create a DNSv6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + &Dns6Handle + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + (VOID **) &Dns6, + Private->Image, + Private->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Configure DNS6 instance for the DNS server address and protocol. + // + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); + Dns6ConfigData.DnsServerCount = 1; + Dns6ConfigData.DnsServerList = DnsServerList; + Dns6ConfigData.EnableDnsCache = TRUE; + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6); + Status = Dns6->Configure ( + Dns6, + &Dns6ConfigData + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Token.Status = EFI_NOT_READY; + IsDone = FALSE; + // + // Create event to set the IsDone flag when name resolution is finished. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Start asynchronous name resolution. + // + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); + if (EFI_ERROR (Status)) { + goto Exit; + } + + while (!IsDone) { + Dns6->Poll (Dns6); + } + + // + // Name resolution is done, check result. + // + Status = Token.Status; + if (!EFI_ERROR (Status)) { + if (Token.RspData.H2AData == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // We just return the first IPv6 address from DNS protocol. + // + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); + Status = EFI_SUCCESS; + } + +Exit: + FreePool (HostName); + + if (Token.Event != NULL) { + gBS->CloseEvent (Token.Event); + } + if (Token.RspData.H2AData != NULL) { + if (Token.RspData.H2AData->IpList != NULL) { + FreePool (Token.RspData.H2AData->IpList); + } + FreePool (Token.RspData.H2AData); + } + + if (Dns6 != NULL) { + Dns6->Configure (Dns6, NULL); + + gBS->CloseProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + Private->Image, + Private->Controller + ); + } + + if (Dns6Handle != NULL) { + NetLibDestroyServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + Dns6Handle + ); + } + + if (DnsServerList != NULL) { + FreePool (DnsServerList); + } + + return Status; +} /** Parse the Boot File URL option. + @param[in] Private Pointer to PxeBc private data. @param[out] FileName The pointer to the boot file name. @param[in, out] SrvAddr The pointer to the boot server address. @param[in] BootFile The pointer to the boot file URL option data. @@ -232,6 +396,7 @@ PxeBcFreeBootFileOption ( **/ EFI_STATUS PxeBcExtractBootFileUrl ( + IN PXEBC_PRIVATE_DATA *Private, OUT UINT8 **FileName, IN OUT EFI_IPv6_ADDRESS *SrvAddr, IN CHAR8 *BootFile, @@ -247,8 +412,12 @@ PxeBcExtractBootFileUrl ( CHAR8 *ServerAddressOption; CHAR8 *ServerAddress; CHAR8 *ModeStr; + CHAR16 *HostName; + BOOLEAN IpExpressedUrl; + UINTN Len; EFI_STATUS Status; + IpExpressedUrl = TRUE; // // The format of the Boot File URL option is: // @@ -264,8 +433,8 @@ PxeBcExtractBootFileUrl ( // // - // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format - // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME + // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be + // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME // As an example where the BOOTFILE_NAME is the EFI loader and // SERVER_ADDRESS is the ASCII encoding of an IPV6 address. // @@ -291,43 +460,76 @@ PxeBcExtractBootFileUrl ( // Get the part of SERVER_ADDRESS string. // ServerAddressOption = TmpStr; - if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; - } + if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) { + ServerAddressOption ++; + ServerAddress = ServerAddressOption; + while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) { + ServerAddress++; + } + + if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + *ServerAddress = '\0'; + + // + // Convert the string of server address to Ipv6 address format and store it. + // + Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); + if (EFI_ERROR (Status)) { + FreePool (TmpStr); + return Status; + } - ServerAddressOption ++; - ServerAddress = ServerAddressOption; - while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) { - ServerAddress++; - } + } else { + IpExpressedUrl = FALSE; + ServerAddress = ServerAddressOption; + while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { + ServerAddress++; + } - if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; - } + if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + *ServerAddress = '\0'; - *ServerAddress = '\0'; + Len = AsciiStrSize (ServerAddressOption); + HostName = AllocateZeroPool (Len * sizeof (CHAR16)); + if (HostName == NULL) { + FreePool (TmpStr); + return EFI_OUT_OF_RESOURCES; + } + AsciiStrToUnicodeStrS ( + ServerAddressOption, + HostName, + Len + ); - // - // Convert the string of server address to Ipv6 address format and store it. - // - Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); - if (EFI_ERROR (Status)) { - FreePool (TmpStr); - return Status; + // + // Perform DNS resolution. + // + Status = PxeBcDns6 (Private,HostName, SrvAddr); + if (EFI_ERROR (Status)) { + FreePool (TmpStr); + return Status; + } } // // Get the part of BOOTFILE_NAME string. // BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1); - if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; + if (IpExpressedUrl) { + if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + ++BootFileNamePtr; } - ++BootFileNamePtr; BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1); if (BootFileNameLen != 0 || FileName != NULL) { // @@ -471,17 +673,19 @@ PxeBcParseDhcp6Packet ( // while (Offset < Length) { - if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) { + if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) { Options[PXEBC_DHCP6_IDX_IA_NA] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) { // // The server sends this option to inform the client about an URL to a boot file. // Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) { Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) { Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option; + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) { + Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; } Offset += (NTOHS (Option->OpLen) + 4); @@ -497,7 +701,7 @@ PxeBcParseDhcp6Packet ( Option = PxeBcParseDhcp6Options ( Option->Data + 12, NTOHS (Option->OpLen), - PXEBC_DHCP6_OPT_STATUS_CODE + DHCP6_OPT_STATUS_CODE ); if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { IsProxyOffer = FALSE; @@ -713,7 +917,7 @@ PxeBcRequestBootService ( Option = PxeBcDhcp6SeekOption ( ProxyOffer->Dhcp6.Option, ProxyOffer->Length - 4, - PXEBC_DHCP6_OPT_SERVER_ID + DHCP6_OPT_SERVER_ID ); if (Option == NULL) { return EFI_NOT_FOUND; @@ -732,7 +936,7 @@ PxeBcRequestBootService ( OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); if (OpCode != EFI_DHCP6_IA_TYPE_NA && OpCode != EFI_DHCP6_IA_TYPE_TA && - OpCode != PXEBC_DHCP6_OPT_SERVER_ID + OpCode != DHCP6_OPT_SERVER_ID ) { // // Copy all the options except IA option and Server ID @@ -751,7 +955,7 @@ PxeBcRequestBootService ( Option = PxeBcDhcp6SeekOption ( Discover->DhcpOptions, (UINT32)(RequestLen - 4), - PXEBC_DHCP6_OPT_ELAPSED_TIME + DHCP6_OPT_ELAPSED_TIME ); if (Option != NULL) { CalcElapsedTime (Private); @@ -864,6 +1068,7 @@ PxeBcRetryDhcp6Binl ( // Parse out the next server address from the last offer, and store it // Status = PxeBcExtractBootFileUrl ( + Private, &Private->BootFileName, &Private->ServerIp.v6, (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), @@ -1093,8 +1298,9 @@ PxeBcSelectDhcp6Offer ( @param[in] Private The pointer to PXEBC_PRIVATE_DATA. - @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. - @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. + @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. **/ EFI_STATUS @@ -1115,6 +1321,17 @@ PxeBcHandleDhcp6Offer ( Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6; Status = EFI_SUCCESS; + // + // First try to cache DNS server address if DHCP6 offer provides. + // + if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { + Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); + if (Private->DnsServer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); + } + if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { // // DhcpBinl offer is selected, so need try to request bootfilename by this offer. @@ -1702,6 +1919,14 @@ PxeBcDhcp6CallBack ( switch (Dhcp6Event) { case Dhcp6SendSolicit: + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // If the to be sent packet exceeds the maximum length, abort the DHCP process. + // + Status = EFI_ABORTED; + break; + } + // // Record the first Solicate msg time // @@ -1717,6 +1942,12 @@ PxeBcDhcp6CallBack ( case Dhcp6RcvdAdvertise: Status = EFI_NOT_READY; + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // Ignore the incoming packets which exceed the maximum length. + // + break; + } if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { // // Cache the dhcp offers to OfferBuffer[] for select later, and record @@ -1727,6 +1958,14 @@ PxeBcDhcp6CallBack ( break; case Dhcp6SendRequest: + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // If the to be sent packet exceeds the maximum length, abort the DHCP process. + // + Status = EFI_ABORTED; + break; + } + // // Store the request packet as seed packet for discover. // @@ -1758,6 +1997,13 @@ PxeBcDhcp6CallBack ( break; case Dhcp6RcvdReply: + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // Abort the DHCP if the Peply packet exceeds the maximum length. + // + Status = EFI_ABORTED; + break; + } // // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data // without verification. @@ -2073,7 +2319,7 @@ PxeBcDhcp6Sarr ( return Status; } - ASSERT (Mode.Ia->State == Dhcp6Bound); + 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 @@ -2082,7 +2328,12 @@ PxeBcDhcp6Sarr ( // 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); + } + if (Mode.Ia != NULL) { + FreePool (Mode.Ia); + } // // Check the selected offer whether BINL retry is needed. //