From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7B1A31A1E9E for ; Fri, 14 Oct 2016 00:28:45 -0700 (PDT) Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP; 14 Oct 2016 00:28:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,491,1473145200"; d="scan'208";a="19506837" Received: from shwdeopenpsi116.ccr.corp.intel.com ([10.239.9.20]) by fmsmga005.fm.intel.com with ESMTP; 14 Oct 2016 00:28:43 -0700 From: Zhang Lubo To: edk2-devel@lists.01.org Cc: Ye Ting , Fu Siyuan , Wu Jiaxin Date: Fri, 14 Oct 2016 15:28:09 +0800 Message-Id: <1476430089-19556-1-git-send-email-lubo.zhang@intel.com> X-Mailer: git-send-email 1.9.5.msysgit.1 MIME-Version: 1.0 Subject: [patch] NetworkPkg: Add dns support for pxe boot based on IPv6. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Oct 2016 07:28:45 -0000 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BootFileURL option (59) in dhcpv6 is used to deliver the next server address with bootfile name, as an example "tftp://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/BOOTFILE_NAME; mode=octet", it can also be “tftp://domain_name/BOOTFILE_NAME; mode=octet”, this patch is to support this case. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Cc: Ye Ting Cc: Fu Siyuan Cc: Wu Jiaxin --- NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c | 18 ++- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 269 +++++++++++++++++++++++++++---- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 5 +- NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h | 3 + NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf | 4 +- 5 files changed, 261 insertions(+), 38 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c index 8eff13c..fc50a82 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c @@ -619,31 +619,33 @@ PxeBcDhcp6BootInfo ( } ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); // + // Set the station address to IP layer. + // + Status = PxeBcSetIp6Address (Private); + if (EFI_ERROR (Status)) { + return Status; + } + + + // // Parse (m)tftp server ip address and bootfile name. // Status = PxeBcExtractBootFileUrl ( + Private, &Private->BootFileName, &Private->ServerIp.v6, (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) ); if (EFI_ERROR (Status)) { return Status; } // - // Set the station address to IP layer. - // - Status = PxeBcSetIp6Address (Private); - if (EFI_ERROR (Status)) { - return Status; - } - - // // Parse the value of boot file size. // if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) { // // Parse it out if have the boot file parameter option. diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index 41d3d30..45377e3 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -91,14 +91,15 @@ PxeBcBuildDhcp6Options ( // // Append client option request option // OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO); - OptList[Index]->OpLen = HTONS (4); + OptList[Index]->OpLen = HTONS (6); OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data; 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 @@ -214,14 +215,177 @@ PxeBcFreeBootFileOption ( RemoveEntryList (Entry); FreePool (Node); } } +/** + 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. @param[in] Length The length of the boot file URL option data. @@ -230,10 +394,11 @@ PxeBcFreeBootFileOption ( @retval EFI_NOT_READY Read the input key from the keybroad has not finish. **/ EFI_STATUS PxeBcExtractBootFileUrl ( + IN PXEBC_PRIVATE_DATA *Private, OUT UINT8 **FileName, IN OUT EFI_IPv6_ADDRESS *SrvAddr, IN CHAR8 *BootFile, IN UINT16 Length ) @@ -245,12 +410,16 @@ PxeBcExtractBootFileUrl ( CHAR8 *TmpStr; CHAR8 TmpChar; 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: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -262,12 +431,12 @@ 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. // PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); @@ -289,47 +458,80 @@ 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) { // // Remove trailing mode=octet if present and ignore. All other modes are // invalid for netboot6, so reject them. @@ -480,10 +682,12 @@ PxeBcParseDhcp6Packet ( Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option; } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) { Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option; } 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); Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); } @@ -862,10 +1066,11 @@ PxeBcRetryDhcp6Binl ( 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, &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) ); @@ -1113,10 +1318,18 @@ PxeBcHandleDhcp6Offer ( SelectIndex = (UINT32) (Private->SelectIndex - 1); ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); 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)); + 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. // if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) { diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h index a6d52f9..9493b16 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h @@ -31,11 +31,12 @@ #define PXEBC_DHCP6_IDX_IA_NA 0 #define PXEBC_DHCP6_IDX_BOOT_FILE_URL 1 #define PXEBC_DHCP6_IDX_BOOT_FILE_PARAM 2 #define PXEBC_DHCP6_IDX_VENDOR_CLASS 3 -#define PXEBC_DHCP6_IDX_MAX 4 +#define PXEBC_DHCP6_IDX_DNS_SERVER 4 +#define PXEBC_DHCP6_IDX_MAX 5 #define PXEBC_DHCP6_BOOT_FILE_URL_PREFIX "tftp://" #define PXEBC_TFTP_URL_SEPARATOR '/' #define PXEBC_ADDR_START_DELIMITER '[' #define PXEBC_ADDR_END_DELIMITER ']' @@ -126,10 +127,11 @@ PxeBcFreeBootFileOption ( /** 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. @param[in] Length Length of the boot file URL option data. @@ -138,10 +140,11 @@ PxeBcFreeBootFileOption ( @retval EFI_NOT_READY Read the input key from the keybroad has not finish. **/ EFI_STATUS PxeBcExtractBootFileUrl ( + IN PXEBC_PRIVATE_DATA *Private, OUT UINT8 **FileName, IN OUT EFI_IPv6_ADDRESS *SrvAddr, IN CHAR8 *BootFile, IN UINT16 Length ); diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h index d0f5e5b..2cdc8bf 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h @@ -30,10 +30,11 @@ #include #include #include #include #include +#include #include #include #include #include #include @@ -134,10 +135,11 @@ struct _PXEBC_PRIVATE_DATA { EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; EFI_DHCP6_PROTOCOL *Dhcp6; EFI_MTFTP6_PROTOCOL *Mtftp6; EFI_UDP6_PROTOCOL *Udp6Read; EFI_UDP6_PROTOCOL *Udp6Write; + EFI_DNS6_PROTOCOL *Dns6; EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; EFI_PXE_BASE_CODE_PROTOCOL PxeBc; EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL LoadFileCallback; EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *PxeBcCallback; @@ -167,10 +169,11 @@ struct _PXEBC_PRIVATE_DATA { EFI_IP_ADDRESS TmpStationIp; EFI_IP_ADDRESS StationIp; EFI_IP_ADDRESS SubnetMask; EFI_IP_ADDRESS GatewayIp; EFI_IP_ADDRESS ServerIp; + EFI_IPv6_ADDRESS *DnsServer; UINT16 CurSrcPort; UINT32 IaId; UINT32 Ip4MaxPacketSize; UINT32 Ip6MaxPacketSize; diff --git a/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf b/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf index c3ca218..6d1102b 100644 --- a/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf +++ b/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf @@ -4,11 +4,11 @@ # This driver provides PXE Base Code Protocol which is used to accessing # PXE-compatible device for network access or booting. It could work together # with an IPv4 stack, an IPv6 stack or both. # # -# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 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 # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php. @@ -93,10 +93,12 @@ gEfiUdp6ProtocolGuid ## TO_START gEfiMtftp6ServiceBindingProtocolGuid ## TO_START gEfiMtftp6ProtocolGuid ## TO_START gEfiDhcp6ServiceBindingProtocolGuid ## TO_START gEfiDhcp6ProtocolGuid ## TO_START + gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES gEfiPxeBaseCodeCallbackProtocolGuid ## SOMETIMES_PRODUCES gEfiPxeBaseCodeProtocolGuid ## BY_START gEfiLoadFileProtocolGuid ## BY_START gEfiAdapterInformationProtocolGuid ## SOMETIMES_CONSUMES -- 1.9.5.msysgit.1