]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/DnsDxe/DnsDhcp.c
NetworkPkg: Add DNS feature support over IPv4 and IPv6.
[mirror_edk2.git] / NetworkPkg / DnsDxe / DnsDhcp.c
diff --git a/NetworkPkg/DnsDxe/DnsDhcp.c b/NetworkPkg/DnsDxe/DnsDhcp.c
new file mode 100644 (file)
index 0000000..4607f7b
--- /dev/null
@@ -0,0 +1,762 @@
+/** @file\r
+Functions implementation related with DHCPv4/v6 for DNS driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+**/\r
+\r
+#include "DnsImpl.h"\r
+\r
+/**\r
+  This function initialize the DHCP4 message instance.\r
+\r
+  This function will pad each item of dhcp4 message packet.\r
+\r
+  @param  Seed             Pointer to the message instance of the DHCP4 packet.\r
+  @param  InterfaceInfo    Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.\r
+\r
+**/\r
+VOID\r
+DnsInitSeedPacket (\r
+  OUT EFI_DHCP4_PACKET               *Seed,\r
+  IN  EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo\r
+  )\r
+{\r
+  EFI_DHCP4_HEADER           *Header;\r
+\r
+  //\r
+  // Get IfType and HwAddressSize from SNP mode data.\r
+  //\r
+  Seed->Size            = sizeof (EFI_DHCP4_PACKET);\r
+  Seed->Length          = sizeof (Seed->Dhcp4);\r
+  Header                = &Seed->Dhcp4.Header;\r
+  ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
+  Header->OpCode        = DHCP4_OPCODE_REQUEST;\r
+  Header->HwType        = InterfaceInfo->IfType;\r
+  Header->HwAddrLen     = (UINT8) InterfaceInfo->HwAddressSize;\r
+  CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);\r
+\r
+  Seed->Dhcp4.Magik     = DHCP4_MAGIC;\r
+  Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;\r
+}\r
+\r
+/**\r
+  The common notify function. \r
+\r
+  @param[in]  Event   The event signaled.\r
+  @param[in]  Context The context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DhcpCommonNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  if ((Event == NULL) || (Context == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  *((BOOLEAN *) Context) = TRUE;\r
+}\r
+\r
+/**\r
+  Parse the ACK to get required information\r
+\r
+  @param  Dhcp4            The DHCP4 protocol.\r
+  @param  Packet           Packet waiting for parse.\r
+  @param  DnsServerInfor   The required Dns4 server information.\r
+\r
+  @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.\r
+  @retval EFI_NO_MAPPING        DHCP failed to acquire address and other information.\r
+  @retval EFI_DEVICE_ERROR      Other errors as indicated.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseDhcp4Ack (\r
+  IN EFI_DHCP4_PROTOCOL         *Dhcp4,\r
+  IN EFI_DHCP4_PACKET           *Packet,\r
+  IN DNS4_SERVER_INFOR          *DnsServerInfor\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  OptionCount;\r
+  EFI_DHCP4_PACKET_OPTION **OptionList;\r
+  UINT32                  ServerCount;\r
+  EFI_IPv4_ADDRESS        *ServerList;\r
+  UINT32                  Index;\r
+  UINT32                  Count;\r
+\r
+  ServerCount = 0;\r
+  ServerList = NULL;\r
+\r
+  OptionCount = 0;\r
+  OptionList  = NULL;\r
+\r
+  Status      = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+  if (OptionList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (OptionList);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  for (Index = 0; Index < OptionCount; Index++) {\r
+    //\r
+    // Get DNS server addresses\r
+    //\r
+    if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {\r
+\r
+      if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        break;\r
+      }\r
+\r
+      ServerCount = OptionList[Index]->Length/4;\r
+      ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));\r
+      if (ServerList == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      for(Count=0; Count < ServerCount; Count++){\r
+        CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));\r
+      }\r
+\r
+      *(DnsServerInfor->ServerCount) = ServerCount;\r
+      DnsServerInfor->ServerList     = ServerList;\r
+\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  gBS->FreePool (OptionList);\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol \r
+  instance to intercept events that occurs in the DHCPv6 Information Request\r
+  exchange process.\r
+\r
+  @param  This                  Pointer to the EFI_DHCP6_PROTOCOL instance that \r
+                                is used to configure this  callback function.\r
+  @param  Context               Pointer to the context that is initialized in\r
+                                the EFI_DHCP6_PROTOCOL.InfoRequest().\r
+  @param  Packet                Pointer to Reply packet that has been received.\r
+                                The EFI DHCPv6 Protocol instance is responsible\r
+                                for freeing the buffer.\r
+\r
+  @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.\r
+  @retval EFI_DEVICE_ERROR      Other errors as indicated.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ParseDhcp6Ack (\r
+  IN EFI_DHCP6_PROTOCOL          *This,\r
+  IN VOID                        *Context,\r
+  IN EFI_DHCP6_PACKET            *Packet\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT32                      OptionCount;\r
+  EFI_DHCP6_PACKET_OPTION     **OptionList;\r
+  DNS6_SERVER_INFOR           *DnsServerInfor;\r
+  UINT32                      ServerCount;\r
+  EFI_IPv6_ADDRESS            *ServerList;\r
+  UINT32                      Index;\r
+  UINT32                      Count;\r
\r
+  OptionCount = 0;\r
+  ServerCount = 0;\r
+  ServerList  = NULL;\r
+  \r
+  Status      = This->Parse (This, Packet, &OptionCount, NULL);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
+  if (OptionList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (OptionList);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  DnsServerInfor = (DNS6_SERVER_INFOR *) Context;\r
+\r
+  for (Index = 0; Index < OptionCount; Index++) {\r
+    OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);\r
+    OptionList[Index]->OpLen  = NTOHS (OptionList[Index]->OpLen);\r
+\r
+    //\r
+    // Get DNS server addresses from this reply packet.\r
+    //\r
+    if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {\r
+\r
+      if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        gBS->FreePool (OptionList);\r
+        return Status;\r
+      }\r
+      \r
+      ServerCount = OptionList[Index]->OpLen/16;\r
+      ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));\r
+      if (ServerList == NULL) {\r
+        gBS->FreePool (OptionList);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      for(Count=0; Count < ServerCount; Count++){\r
+        CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));\r
+      }\r
+\r
+      *(DnsServerInfor->ServerCount) = ServerCount;\r
+      DnsServerInfor->ServerList     = ServerList;\r
+    }\r
+  }\r
+\r
+  gBS->FreePool (OptionList);\r
+  \r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Parse the DHCP ACK to get Dns4 server information.\r
+\r
+  @param  Instance         The DNS instance.\r
+  @param  DnsServerCount   Retrieved Dns4 server Ip count.\r
+  @param  DnsServerList    Retrieved Dns4 server Ip list.\r
+\r
+  @retval EFI_SUCCESS           The Dns4 information is got from the DHCP ACK.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.\r
+  @retval EFI_NO_MEDIA          There was a media error.\r
+  @retval Others                Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDns4ServerFromDhcp4 (\r
+  IN  DNS_INSTANCE               *Instance,\r
+  OUT UINT32                     *DnsServerCount,\r
+  OUT EFI_IPv4_ADDRESS           **DnsServerList\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          Image;\r
+  EFI_HANDLE                          Controller;\r
+  BOOLEAN                             MediaPresent;\r
+  EFI_HANDLE                          MnpChildHandle;  \r
+  EFI_MANAGED_NETWORK_PROTOCOL        *Mnp;\r
+  EFI_MANAGED_NETWORK_CONFIG_DATA     MnpConfigData;\r
+  EFI_HANDLE                          Dhcp4Handle;  \r
+  EFI_DHCP4_PROTOCOL                  *Dhcp4;\r
+  EFI_IP4_CONFIG2_PROTOCOL            *Ip4Config2;\r
+  UINTN                               DataSize;\r
+  VOID                                *Data;\r
+  EFI_IP4_CONFIG2_INTERFACE_INFO      *InterfaceInfo;\r
+  EFI_DHCP4_PACKET                    SeedPacket;\r
+  EFI_DHCP4_PACKET_OPTION             *ParaList[2];\r
+  DNS4_SERVER_INFOR                   DnsServerInfor;\r
+\r
+  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;\r
+  BOOLEAN                             IsDone;\r
+  UINTN                               Index;\r
+  \r
+  Image                      = Instance->Service->ImageHandle;\r
+  Controller                 = Instance->Service->ControllerHandle;\r
+\r
+  MnpChildHandle             = NULL;\r
+  Mnp                        = NULL;\r
+  \r
+  Dhcp4Handle                = NULL;\r
+  Dhcp4                      = NULL;\r
+\r
+  Ip4Config2                 = NULL;\r
+  DataSize                   = 0;\r
+  Data                       = NULL;\r
+  InterfaceInfo              = NULL;\r
+\r
+  ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));\r
+  \r
+  ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));\r
+  \r
+  ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
+  \r
+  DnsServerInfor.ServerCount = DnsServerCount;\r
+\r
+  IsDone = FALSE;\r
+\r
+  //\r
+  // Check media.\r
+  //\r
+  MediaPresent = TRUE;\r
+  NetLibDetectMedia (Controller, &MediaPresent);\r
+  if (!MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  //\r
+  // Create a Mnp child instance, get the protocol and config for it.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Controller,\r
+             Image,\r
+             &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+             &MnpChildHandle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  MnpChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  (VOID **) &Mnp,\r
+                  Image,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  MnpConfigData.ReceivedQueueTimeoutValue = 0;\r
+  MnpConfigData.TransmitQueueTimeoutValue = 0;\r
+  MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;\r
+  MnpConfigData.EnableUnicastReceive      = TRUE;\r
+  MnpConfigData.EnableMulticastReceive    = TRUE;\r
+  MnpConfigData.EnableBroadcastReceive    = TRUE;\r
+  MnpConfigData.EnablePromiscuousReceive  = FALSE;\r
+  MnpConfigData.FlushQueuesOnReset        = TRUE;\r
+  MnpConfigData.EnableReceiveTimestamps   = FALSE;\r
+  MnpConfigData.DisableBackgroundPolling  = FALSE;\r
+\r
+  Status = Mnp->Configure(Mnp, &MnpConfigData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Create a DHCP4 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Controller,\r
+             Image,\r
+             &gEfiDhcp4ServiceBindingProtocolGuid,\r
+             &Dhcp4Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Dhcp4Handle,\r
+                  &gEfiDhcp4ProtocolGuid,\r
+                  (VOID **) &Dhcp4,\r
+                  Image,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Get Ip4Config2 instance info.\r
+  //\r
+  Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);\r
+  if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Data = AllocateZeroPool (DataSize);\r
+  if (Data == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;\r
+  \r
+  //\r
+  // Build required Token.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  DhcpCommonNotify,\r
+                  &IsDone,\r
+                  &Token.CompletionEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
+  \r
+  Token.RemotePort = 67;\r
+\r
+  Token.ListenPointCount = 1;\r
+  \r
+  Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));\r
+  if (Token.ListenPoints == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (Instance->Dns4CfgData.UseDefaultSetting) {\r
+    CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));\r
+    CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));\r
+  } else {\r
+    CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));\r
+    CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));\r
+  }\r
+  \r
+  Token.ListenPoints[0].ListenPort = 68;\r
+  \r
+  Token.TimeoutValue = DNS_TIME_TO_GETMAP;\r
+\r
+  DnsInitSeedPacket (&SeedPacket, InterfaceInfo);\r
+\r
+  ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));\r
+  if (ParaList[0] == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  ParaList[0]->OpCode  = DHCP4_TAG_TYPE;\r
+  ParaList[0]->Length  = 1;\r
+  ParaList[0]->Data[0] = DHCP4_MSG_INFORM;\r
+  \r
+  ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));\r
+  if (ParaList[1] == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  ParaList[1]->OpCode  = DHCP4_TAG_PARA_LIST;\r
+  ParaList[1]->Length  = 1;\r
+  ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;\r
+\r
+  Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet); \r
+\r
+  Token.Packet->Dhcp4.Header.Xid      = HTONL(NET_RANDOM (NetRandomInitSeed ()));\r
+  \r
+  Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);\r
+  \r
+  if (Instance->Dns4CfgData.UseDefaultSetting) {\r
+    CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));\r
+  } else {\r
+    CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));\r
+  }\r
+  \r
+  CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize); \r
+  \r
+  Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);\r
+\r
+  //\r
+  // TransmitReceive Token\r
+  //\r
+  Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Poll the packet\r
+  //\r
+  do {\r
+    Status = Mnp->Poll (Mnp);\r
+  } while (!IsDone);\r
+  \r
+  //\r
+  // Parse the ACK to get required information if received done.\r
+  //\r
+  if (IsDone && !EFI_ERROR (Token.Status)) {\r
+    for (Index = 0; Index < Token.ResponseCount; Index++) {\r
+      Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    *DnsServerList = DnsServerInfor.ServerList;\r
+  } else {\r
+    Status = Token.Status;\r
+  }\r
+  \r
+ON_EXIT:\r
+\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  for (Index = 0; Index < 2; Index++) {\r
+    if (ParaList[Index] != NULL) {\r
+      FreePool (ParaList[Index]);\r
+    }\r
+  }\r
+\r
+  if (Token.ListenPoints) {\r
+    FreePool (Token.ListenPoints);\r
+  }\r
+\r
+  if (Token.Packet) {\r
+    FreePool (Token.Packet);\r
+  }\r
+  \r
+  if (Token.ResponseList != NULL) {\r
+    FreePool (Token.ResponseList);\r
+  }\r
+  \r
+  if (Token.CompletionEvent != NULL) {\r
+    gBS->CloseEvent (Token.CompletionEvent);\r
+  }\r
+  \r
+  if (Dhcp4 != NULL) {\r
+    Dhcp4->Stop (Dhcp4);\r
+    Dhcp4->Configure (Dhcp4, NULL);\r
+\r
+    gBS->CloseProtocol (\r
+           Dhcp4Handle,\r
+           &gEfiDhcp4ProtocolGuid,\r
+           Image,\r
+           Controller\r
+           );\r
+  }\r
+  \r
+  if (Dhcp4Handle != NULL) {\r
+    NetLibDestroyServiceChild (\r
+      Controller,\r
+      Image,\r
+      &gEfiDhcp4ServiceBindingProtocolGuid,\r
+      Dhcp4Handle\r
+      );\r
+  }\r
+\r
+  if (Mnp != NULL) {\r
+    Mnp->Configure (Mnp, NULL);\r
+\r
+    gBS->CloseProtocol (\r
+           MnpChildHandle,\r
+           &gEfiManagedNetworkProtocolGuid,\r
+           Image,\r
+           Controller\r
+           );\r
+  }\r
+  \r
+  NetLibDestroyServiceChild (\r
+    Controller,\r
+    Image,\r
+    &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+    MnpChildHandle\r
+    );\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Parse the DHCP ACK to get Dns6 server information.\r
+\r
+  @param  Image            The handle of the driver image.\r
+  @param  Controller       The handle of the controller.\r
+  @param  DnsServerCount   Retrieved Dns6 server Ip count.\r
+  @param  DnsServerList    Retrieved Dns6 server Ip list.\r
+\r
+  @retval EFI_SUCCESS           The Dns6 information is got from the DHCP ACK.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.\r
+  @retval EFI_NO_MEDIA          There was a media error.\r
+  @retval Others                Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDns6ServerFromDhcp6 (\r
+  IN  EFI_HANDLE                 Image,\r
+  IN  EFI_HANDLE                 Controller,\r
+  OUT UINT32                     *DnsServerCount,\r
+  OUT EFI_IPv6_ADDRESS           **DnsServerList\r
+  )\r
+{\r
+  EFI_HANDLE                Dhcp6Handle;\r
+  EFI_DHCP6_PROTOCOL        *Dhcp6;\r
+  EFI_STATUS                Status;\r
+  EFI_STATUS                TimerStatus;\r
+  EFI_DHCP6_PACKET_OPTION   *Oro;\r
+  EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;\r
+  EFI_EVENT                 Timer;\r
+  BOOLEAN                   MediaPresent;\r
+  DNS6_SERVER_INFOR         DnsServerInfor;\r
+\r
+  Dhcp6Handle = NULL;\r
+  Dhcp6       = NULL;\r
+  Oro         = NULL;\r
+  Timer       = NULL;\r
+\r
+  ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));\r
+\r
+  DnsServerInfor.ServerCount = DnsServerCount;\r
+\r
+  //\r
+  // Check media status before doing DHCP.\r
+  //\r
+  MediaPresent = TRUE;\r
+  NetLibDetectMedia (Controller, &MediaPresent);\r
+  if (!MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  //\r
+  // Create a DHCP6 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Controller,\r
+             Image,\r
+             &gEfiDhcp6ServiceBindingProtocolGuid,\r
+             &Dhcp6Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Dhcp6Handle,\r
+                  &gEfiDhcp6ProtocolGuid,\r
+                  (VOID **) &Dhcp6,\r
+                  Image,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);\r
+  if (Oro == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Ask the server to reply with DNS options.\r
+  // All members in EFI_DHCP6_PACKET_OPTION are in network order.\r
+  //\r
+  Oro->OpCode  = HTONS (DHCP6_TAG_DNS_REQUEST);\r
+  Oro->OpLen   = HTONS (2);\r
+  Oro->Data[1] = DHCP6_TAG_DNS_SERVER;\r
+\r
+  InfoReqReXmit.Irt = 4;\r
+  InfoReqReXmit.Mrc = 1;\r
+  InfoReqReXmit.Mrt = 10;\r
+  InfoReqReXmit.Mrd = 30;\r
+\r
+  Status = Dhcp6->InfoRequest (\r
+                    Dhcp6,\r
+                    TRUE,\r
+                    Oro,\r
+                    0,\r
+                    NULL,\r
+                    &InfoReqReXmit,\r
+                    NULL,\r
+                    ParseDhcp6Ack,\r
+                    &DnsServerInfor\r
+                    );\r
+  if (Status == EFI_NO_MAPPING) {\r
+    Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = gBS->SetTimer (\r
+                    Timer,\r
+                    TimerRelative,\r
+                    DNS_TIME_TO_GETMAP * TICKS_PER_SECOND\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    do {\r
+      TimerStatus = gBS->CheckEvent (Timer);\r
+      if (!EFI_ERROR (TimerStatus)) {\r
+        Status = Dhcp6->InfoRequest (\r
+                          Dhcp6,\r
+                          TRUE,\r
+                          Oro,\r
+                          0,\r
+                          NULL,\r
+                          &InfoReqReXmit,\r
+                          NULL,\r
+                          ParseDhcp6Ack,\r
+                          &DnsServerInfor\r
+                          );\r
+      }\r
+    } while (TimerStatus == EFI_NOT_READY);\r
+  }\r
+  \r
+  *DnsServerList  = DnsServerInfor.ServerList;\r
+\r
+ON_EXIT:\r
+\r
+  if (Oro != NULL) {\r
+    FreePool (Oro);\r
+  }  \r
+\r
+  if (Timer != NULL) {\r
+    gBS->CloseEvent (Timer);\r
+  }\r
+\r
+  if (Dhcp6 != NULL) {\r
+    gBS->CloseProtocol (\r
+           Dhcp6Handle,\r
+           &gEfiDhcp6ProtocolGuid,\r
+           Image,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  NetLibDestroyServiceChild (\r
+    Controller,\r
+    Image,\r
+    &gEfiDhcp6ServiceBindingProtocolGuid,\r
+    Dhcp6Handle\r
+    );\r
+\r
+  return Status;\r
+  \r
+}\r
+\r