]> git.proxmox.com Git - mirror_edk2.git/commitdiff
NetworkPkg: Add dns support for pxe boot based on IPv6.
authorZhang Lubo <lubo.zhang@intel.com>
Fri, 14 Oct 2016 07:12:09 +0000 (15:12 +0800)
committerJiaxin Wu <jiaxin.wu@intel.com>
Wed, 26 Oct 2016 08:42:35 +0000 (16:42 +0800)
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 <lubo.zhang@intel.com>
Cc: Ye Ting <ting.ye@intel.com>
Cc: Fu Siyuan <siyuan.fu@intel.com>
Cc: Wu Jiaxin <jiaxin.wu@intel.com>
Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h
NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h
NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf

index 8eff13c4efda4048b844d80d50fd8840e1d00cd2..fc50a82959d40bf162741fa1a64ed17c45067def 100644 (file)
@@ -620,10 +620,20 @@ PxeBcDhcp6BootInfo (
 \r
   ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
 \r
+  //\r
+  // Set the station address to IP layer.\r
+  //\r
+  Status = PxeBcSetIp6Address (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+\r
   //\r
   // Parse (m)tftp server ip address and bootfile name.\r
   //\r
   Status = PxeBcExtractBootFileUrl (\r
+             Private,\r
              &Private->BootFileName,\r
              &Private->ServerIp.v6,\r
              (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
@@ -633,14 +643,6 @@ PxeBcDhcp6BootInfo (
     return Status;\r
   }\r
 \r
-  //\r
-  // Set the station address to IP layer.\r
-  //\r
-  Status = PxeBcSetIp6Address (Private);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-  \r
   //\r
   // Parse the value of boot file size.\r
   //\r
index 41d3d30a12d50c563a3935cd68e7d8fa082bc486..45377e3626463410a968f3ec51ac1198ef6a9358 100644 (file)
@@ -93,10 +93,11 @@ PxeBcBuildDhcp6Options (
   // Append client option request option\r
   //\r
   OptList[Index]->OpCode     = HTONS (DHCP6_OPT_ORO);\r
-  OptList[Index]->OpLen      = HTONS (4);\r
+  OptList[Index]->OpLen      = HTONS (6);\r
   OptEnt.Oro                 = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
   OptEnt.Oro->OpCode[0]      = HTONS(DHCP6_OPT_BOOT_FILE_URL);\r
   OptEnt.Oro->OpCode[1]      = HTONS(DHCP6_OPT_BOOT_FILE_PARAM);\r
+  OptEnt.Oro->OpCode[2]      = HTONS(DHCP6_OPT_DNS_SERVERS);\r
   Index++;\r
   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
 \r
@@ -216,10 +217,173 @@ PxeBcFreeBootFileOption (
   }\r
 }\r
 \r
+/**\r
+  Retrieve the boot server address using the EFI_DNS6_PROTOCOL.\r
+\r
+  @param[in]  Private             Pointer to PxeBc private data.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.\r
+  \r
+**/\r
+EFI_STATUS\r
+PxeBcDns6 (\r
+  IN PXEBC_PRIVATE_DATA           *Private,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv6_ADDRESS         *IpAddress                \r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_DNS6_PROTOCOL               *Dns6;\r
+  EFI_DNS6_CONFIG_DATA            Dns6ConfigData;\r
+  EFI_DNS6_COMPLETION_TOKEN       Token;\r
+  EFI_HANDLE                      Dns6Handle;\r
+  EFI_IPv6_ADDRESS                *DnsServerList;\r
+  BOOLEAN                         IsDone;\r
+  \r
+  Dns6                = NULL;\r
+  Dns6Handle          = NULL;\r
+  DnsServerList       = Private->DnsServer;\r
+  ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
+\r
+  //\r
+  // Create a DNSv6 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Private->Controller,\r
+             Private->Image,\r
+             &gEfiDns6ServiceBindingProtocolGuid,\r
+             &Dns6Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  } \r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  Dns6Handle,\r
+                  &gEfiDns6ProtocolGuid,\r
+                  (VOID **) &Dns6,\r
+                  Private->Image,\r
+                  Private->Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Configure DNS6 instance for the DNS server address and protocol.\r
+  //\r
+  ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
+  Dns6ConfigData.DnsServerCount = 1;\r
+  Dns6ConfigData.DnsServerList  = DnsServerList;\r
+  Dns6ConfigData.EnableDnsCache = TRUE;\r
+  Dns6ConfigData.Protocol       = EFI_IP_PROTO_UDP;\r
+  IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6);\r
+  Status = Dns6->Configure (\r
+                   Dns6,\r
+                   &Dns6ConfigData\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Token.Status = EFI_NOT_READY;\r
+  IsDone       = FALSE;\r
+  //\r
+  // Create event to set the  IsDone flag when name resolution is finished.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  PxeBcCommonNotify,\r
+                  &IsDone,\r
+                  &Token.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Start asynchronous name resolution.\r
+  //\r
+  Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  while (!IsDone) {\r
+    Dns6->Poll (Dns6);\r
+  }\r
+\r
+  //\r
+  // Name resolution is done, check result.\r
+  //\r
+  Status = Token.Status;  \r
+  if (!EFI_ERROR (Status)) {\r
+    if (Token.RspData.H2AData == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // We just return the first IPv6 address from DNS protocol.\r
+    //\r
+    IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  \r
+Exit:\r
+  FreePool (HostName);\r
+\r
+  if (Token.Event != NULL) {\r
+    gBS->CloseEvent (Token.Event);\r
+  }\r
+  if (Token.RspData.H2AData != NULL) {\r
+    if (Token.RspData.H2AData->IpList != NULL) {\r
+      FreePool (Token.RspData.H2AData->IpList);\r
+    }\r
+    FreePool (Token.RspData.H2AData);\r
+  }\r
+\r
+  if (Dns6 != NULL) {\r
+    Dns6->Configure (Dns6, NULL);\r
+    \r
+    gBS->CloseProtocol (\r
+           Dns6Handle,\r
+           &gEfiDns6ProtocolGuid,\r
+           Private->Image,\r
+           Private->Controller\r
+           );\r
+  }\r
+\r
+  if (Dns6Handle != NULL) {\r
+    NetLibDestroyServiceChild (\r
+      Private->Controller,\r
+      Private->Image,\r
+      &gEfiDns6ServiceBindingProtocolGuid,\r
+      Dns6Handle\r
+      );\r
+  }\r
+\r
+  if (DnsServerList != NULL) {\r
+    FreePool (DnsServerList);\r
+  }\r
+  \r
+  return Status;  \r
+}\r
 \r
 /**\r
   Parse the Boot File URL option.\r
 \r
+  @param[in]      Private      Pointer to PxeBc private data.\r
   @param[out]     FileName     The pointer to the boot file name.\r
   @param[in, out] SrvAddr      The pointer to the boot server address.\r
   @param[in]      BootFile     The pointer to the boot file URL option data.\r
@@ -232,6 +396,7 @@ PxeBcFreeBootFileOption (
 **/\r
 EFI_STATUS\r
 PxeBcExtractBootFileUrl (\r
+  IN PXEBC_PRIVATE_DATA      *Private,\r
      OUT UINT8               **FileName,\r
   IN OUT EFI_IPv6_ADDRESS    *SrvAddr,\r
   IN     CHAR8               *BootFile,\r
@@ -247,8 +412,12 @@ PxeBcExtractBootFileUrl (
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
   CHAR8                      *ModeStr;\r
+  CHAR16                     *HostName;\r
+  BOOLEAN                    IpExpressedUrl;\r
+  UINTN                      Len;\r
   EFI_STATUS                 Status;\r
 \r
+  IpExpressedUrl = TRUE;\r
   //\r
   // The format of the Boot File URL option is:\r
   //\r
@@ -264,8 +433,8 @@ PxeBcExtractBootFileUrl (
   //\r
 \r
   //\r
-  // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format\r
-  // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME\r
+  // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be\r
+  // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME\r
   // As an example where the BOOTFILE_NAME is the EFI loader and\r
   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
   //\r
@@ -291,43 +460,76 @@ PxeBcExtractBootFileUrl (
   // Get the part of SERVER_ADDRESS string.\r
   //\r
   ServerAddressOption = TmpStr;\r
-  if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) {\r
+    ServerAddressOption ++;\r
+    ServerAddress = ServerAddressOption;\r
+    while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
+      ServerAddress++;\r
+    }\r
+    \r
+    if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    \r
+    *ServerAddress = '\0';\r
+    \r
+    //\r
+    // Convert the string of server address to Ipv6 address format and store it.\r
+    //\r
+    Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (TmpStr);\r
+      return Status;\r
+    }\r
 \r
-  ServerAddressOption ++;\r
-  ServerAddress = ServerAddressOption;\r
-  while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
-    ServerAddress++;\r
-  }\r
+  } else {\r
+    IpExpressedUrl = FALSE;\r
+    ServerAddress = ServerAddressOption;\r
+    while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
+      ServerAddress++;\r
+    }\r
 \r
-  if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+    if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    *ServerAddress = '\0';\r
 \r
-  *ServerAddress = '\0';\r
+    Len = AsciiStrSize (ServerAddressOption);\r
+    HostName = AllocateZeroPool (Len * sizeof (CHAR16));\r
+    if (HostName == NULL) {\r
+      FreePool (TmpStr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    AsciiStrToUnicodeStrS (\r
+      ServerAddressOption,\r
+      HostName,\r
+      Len\r
+      );\r
 \r
-  //\r
-  // Convert the string of server address to Ipv6 address format and store it.\r
-  //\r
-  Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (TmpStr);\r
-    return Status;\r
+    //\r
+    // Perform DNS resolution.\r
+    //\r
+    Status = PxeBcDns6 (Private,HostName, SrvAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (TmpStr);\r
+      return Status;\r
+    }\r
   }\r
 \r
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
   BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);\r
-  if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
-    FreePool (TmpStr);\r
-    return EFI_INVALID_PARAMETER;\r
+  if (IpExpressedUrl) {\r
+    if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
+      FreePool (TmpStr);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    ++BootFileNamePtr;\r
   }\r
 \r
-  ++BootFileNamePtr;\r
   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
   if (BootFileNameLen != 0 || FileName != NULL) {\r
     //\r
@@ -482,6 +684,8 @@ PxeBcParseDhcp6Packet (
       Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
     } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
       Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;\r
+    } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {\r
+      Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option;\r
     }\r
 \r
     Offset += (NTOHS (Option->OpLen) + 4);\r
@@ -864,6 +1068,7 @@ PxeBcRetryDhcp6Binl (
     // Parse out the next server address from the last offer, and store it\r
     //\r
     Status = PxeBcExtractBootFileUrl (\r
+               Private,\r
                &Private->BootFileName,\r
                &Private->ServerIp.v6,\r
                (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
@@ -1115,6 +1320,14 @@ PxeBcHandleDhcp6Offer (
   Cache6      = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
   Status      = EFI_SUCCESS;\r
 \r
+  //\r
+  // First try to cache DNS server address if DHCP6 offer provides.\r
+  //\r
+  if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) {\r
+    Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen));\r
+    CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS));\r
+  }\r
+\r
   if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
     //\r
     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
index a6d52f972c5b16105ef9995caebf12a2a4aec9cd..9493b164cbb094d3e8ae99ed0d89103ee28a4086 100644 (file)
@@ -33,7 +33,8 @@
 #define PXEBC_DHCP6_IDX_BOOT_FILE_URL     1\r
 #define PXEBC_DHCP6_IDX_BOOT_FILE_PARAM   2\r
 #define PXEBC_DHCP6_IDX_VENDOR_CLASS      3\r
-#define PXEBC_DHCP6_IDX_MAX               4\r
+#define PXEBC_DHCP6_IDX_DNS_SERVER        4\r
+#define PXEBC_DHCP6_IDX_MAX               5\r
 \r
 #define PXEBC_DHCP6_BOOT_FILE_URL_PREFIX  "tftp://"\r
 #define PXEBC_TFTP_URL_SEPARATOR          '/'\r
@@ -128,6 +129,7 @@ PxeBcFreeBootFileOption (
 /**\r
   Parse the Boot File URL option.\r
 \r
+  @param[in]      Private             Pointer to PxeBc private data.\r
   @param[out]     FileName     The pointer to the boot file name.\r
   @param[in, out] SrvAddr      The pointer to the boot server address.\r
   @param[in]      BootFile     The pointer to the boot file URL option data.\r
@@ -140,6 +142,7 @@ PxeBcFreeBootFileOption (
 **/\r
 EFI_STATUS\r
 PxeBcExtractBootFileUrl (\r
+  IN PXEBC_PRIVATE_DATA      *Private,\r
      OUT UINT8               **FileName,\r
   IN OUT EFI_IPv6_ADDRESS    *SrvAddr,\r
   IN     CHAR8               *BootFile,\r
index d0f5e5b5f26cd9f7a2f3cd2d8c0b97c031249a08..2cdc8bf58921b264d1da60af84ab86e4edeec142 100644 (file)
@@ -32,6 +32,7 @@
 #include <Protocol/Udp6.h>\r
 #include <Protocol/Dhcp4.h>\r
 #include <Protocol/Dhcp6.h>\r
+#include <Protocol/Dns6.h>\r
 #include <Protocol/Mtftp4.h>\r
 #include <Protocol/Mtftp6.h>\r
 #include <Protocol/PxeBaseCode.h>\r
@@ -136,6 +137,7 @@ struct _PXEBC_PRIVATE_DATA {
   EFI_MTFTP6_PROTOCOL                       *Mtftp6;\r
   EFI_UDP6_PROTOCOL                         *Udp6Read;\r
   EFI_UDP6_PROTOCOL                         *Udp6Write;\r
+  EFI_DNS6_PROTOCOL                         *Dns6;\r
 \r
   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
   EFI_PXE_BASE_CODE_PROTOCOL                PxeBc;\r
@@ -169,6 +171,7 @@ struct _PXEBC_PRIVATE_DATA {
   EFI_IP_ADDRESS                            SubnetMask;\r
   EFI_IP_ADDRESS                            GatewayIp;\r
   EFI_IP_ADDRESS                            ServerIp;\r
+  EFI_IPv6_ADDRESS                          *DnsServer;\r
   UINT16                                    CurSrcPort;\r
   UINT32                                    IaId;\r
 \r
index c3ca218ba3e5b7f63f9fa0c24eb8f32c4778f312..6d1102b6b7df7ffeedfd99dd14f3d12573d2d20b 100644 (file)
@@ -6,7 +6,7 @@
 #  with an IPv4 stack, an IPv6 stack or both.\r
 #\r
 #\r
-#  Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
 #\r
 #  This program and the accompanying materials\r
 #  are licensed and made available under the terms and conditions of the BSD License\r
@@ -95,6 +95,8 @@
   gEfiMtftp6ProtocolGuid                               ## TO_START\r
   gEfiDhcp6ServiceBindingProtocolGuid                  ## TO_START\r
   gEfiDhcp6ProtocolGuid                                ## TO_START\r
+  gEfiDns6ServiceBindingProtocolGuid                   ## SOMETIMES_CONSUMES\r
+  gEfiDns6ProtocolGuid                                 ## SOMETIMES_CONSUMES\r
   gEfiPxeBaseCodeCallbackProtocolGuid                  ## SOMETIMES_PRODUCES\r
   gEfiPxeBaseCodeProtocolGuid                          ## BY_START\r
   gEfiLoadFileProtocolGuid                             ## BY_START\r