From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c | 1532 +++++++++++++++++++++++++++++++
 1 file changed, 1532 insertions(+)
 create mode 100644 roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c

(limited to 'roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c')

diff --git a/roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c b/roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c
new file mode 100644
index 000000000..f099da8a5
--- /dev/null
+++ b/roms/edk2/NetworkPkg/DnsDxe/DnsDriver.c
@@ -0,0 +1,1532 @@
+/** @file
+The driver binding and service binding protocol for DnsDxe driver.
+
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DnsImpl.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding = {
+  Dns4DriverBindingSupported,
+  Dns4DriverBindingStart,
+  Dns4DriverBindingStop,
+  DNS_VERSION,
+  NULL,
+  NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding = {
+  Dns6DriverBindingSupported,
+  Dns6DriverBindingStart,
+  Dns6DriverBindingStop,
+  DNS_VERSION,
+  NULL,
+  NULL
+};
+
+EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding = {
+  Dns4ServiceBindingCreateChild,
+  Dns4ServiceBindingDestroyChild
+};
+
+EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding = {
+  Dns6ServiceBindingCreateChild,
+  Dns6ServiceBindingDestroyChild
+};
+
+DNS_DRIVER_DATA          *mDriverData = NULL;
+
+/**
+  Destroy the DNS instance and recycle the resources.
+
+  @param[in]  Instance        The pointer to the DNS instance.
+
+**/
+VOID
+DnsDestroyInstance (
+  IN DNS_INSTANCE         *Instance
+  )
+{
+  ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA));
+
+  ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA));
+
+  if (!NetMapIsEmpty (&Instance->Dns4TxTokens)) {
+    Dns4InstanceCancelToken (Instance, NULL);
+  }
+
+  if (!NetMapIsEmpty (&Instance->Dns6TxTokens)) {
+    Dns6InstanceCancelToken (Instance, NULL);
+  }
+
+  if (Instance->UdpIo!= NULL) {
+    UdpIoFreeIo (Instance->UdpIo);
+  }
+
+  FreePool (Instance);
+}
+
+/**
+  Create the DNS instance and initialize it.
+
+  @param[in]  Service              The pointer to the DNS service.
+  @param[out] Instance             The pointer to the DNS instance.
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
+  @retval EFI_SUCCESS            The DNS instance is created.
+
+**/
+EFI_STATUS
+DnsCreateInstance (
+  IN  DNS_SERVICE         *Service,
+  OUT DNS_INSTANCE        **Instance
+  )
+{
+  DNS_INSTANCE            *DnsIns;
+
+  *Instance = NULL;
+
+  DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE));
+  if (DnsIns == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DnsIns->Signature = DNS_INSTANCE_SIGNATURE;
+  InitializeListHead (&DnsIns->Link);
+  DnsIns->State     = DNS_STATE_UNCONFIGED;
+  DnsIns->InDestroy = FALSE;
+  DnsIns->Service   = Service;
+
+  if (Service->IpVersion == IP_VERSION_4) {
+    CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4));
+    NetMapInit (&DnsIns->Dns4TxTokens);
+  } else {
+    CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6));
+    NetMapInit (&DnsIns->Dns6TxTokens);
+  }
+
+  DnsIns->UdpIo = UdpIoCreateIo (
+                    Service->ControllerHandle, /// NicHandle
+                    Service->ImageHandle,
+                    DnsConfigNullUdp,
+                    Service->IpVersion,
+                    DnsIns
+                    );
+  if (DnsIns->UdpIo == NULL) {
+    FreePool (DnsIns);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  *Instance = DnsIns;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Callback function which provided by user to remove one node in NetDestroyLinkList process.
+
+  @param[in]    Entry           The entry to be removed.
+  @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
+
+  @retval EFI_SUCCESS           The entry has been removed successfully.
+  @retval Others                Fail to remove the entry.
+
+**/
+EFI_STATUS
+EFIAPI
+DnsDestroyChildEntryInHandleBuffer (
+  IN LIST_ENTRY         *Entry,
+  IN VOID               *Context
+  )
+{
+  DNS_INSTANCE                  *Instance;
+  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
+  UINTN                         NumberOfChildren;
+  EFI_HANDLE                    *ChildHandleBuffer;
+
+  if (Entry == NULL || Context == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance = NET_LIST_USER_STRUCT_S (Entry, DNS_INSTANCE, Link, DNS_INSTANCE_SIGNATURE);
+  ServiceBinding    = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
+  NumberOfChildren  = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
+  ChildHandleBuffer = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
+
+  if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) {
+    return EFI_SUCCESS;
+  }
+
+  return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
+}
+
+/**
+  Config a NULL UDP that is used to keep the connection between UDP and DNS.
+
+  Just leave the Udp child unconfigured. When UDP is unloaded,
+    DNS will be informed with DriverBinding Stop.
+
+  @param  UdpIo                  The UDP_IO to configure
+  @param  Context                The opaque parameter to the callback
+
+  @retval EFI_SUCCESS            It always return EFI_SUCCESS directly.
+
+**/
+EFI_STATUS
+EFIAPI
+DnsConfigNullUdp (
+  IN UDP_IO                 *UdpIo,
+  IN VOID                   *Context
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Release all the resource used the DNS service binding instance.
+
+  @param  DnsSb                The Dns service binding instance.
+
+**/
+VOID
+DnsDestroyService (
+  IN DNS_SERVICE     *DnsSb
+  )
+{
+  UdpIoFreeIo (DnsSb->ConnectUdp);
+
+  if (DnsSb->TimerToGetMap != NULL){
+    gBS->CloseEvent (DnsSb->TimerToGetMap);
+  }
+
+  if (DnsSb->Timer != NULL){
+    gBS->CloseEvent (DnsSb->Timer);
+  }
+
+  FreePool (DnsSb);
+}
+
+/**
+  Create then initialize a Dns service binding instance.
+
+  @param  Controller             The controller to install the DNS service
+                                 binding on
+  @param  Image                  The driver binding image of the DNS driver
+  @param  IpVersion              IpVersion for this service
+  @param  Service                The variable to receive the created service
+                                 binding instance.
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource to create the instance.
+  @retval EFI_DEVICE_ERROR       Failed to create a NULL UDP port to keep
+                                 connection  with UDP.
+  @retval EFI_SUCCESS            The service instance is created for the
+                                 controller.
+
+**/
+EFI_STATUS
+DnsCreateService (
+  IN     EFI_HANDLE            Controller,
+  IN     EFI_HANDLE            Image,
+  IN     UINT8                 IpVersion,
+     OUT DNS_SERVICE           **Service
+  )
+{
+  EFI_STATUS             Status;
+  DNS_SERVICE            *DnsSb;
+
+  Status    = EFI_SUCCESS;
+  DnsSb     = NULL;
+
+  *Service  = NULL;
+
+  DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE));
+  if (DnsSb == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DnsSb->Signature = DNS_SERVICE_SIGNATURE;
+
+  if (IpVersion == IP_VERSION_4) {
+    DnsSb->ServiceBinding = mDns4ServiceBinding;
+  } else {
+    DnsSb->ServiceBinding = mDns6ServiceBinding;
+  }
+
+  DnsSb->Dns4ChildrenNum = 0;
+  InitializeListHead (&DnsSb->Dns4ChildrenList);
+
+  DnsSb->Dns6ChildrenNum = 0;
+  InitializeListHead (&DnsSb->Dns6ChildrenList);
+
+  DnsSb->ControllerHandle = Controller;
+  DnsSb->ImageHandle      = Image;
+
+  DnsSb->TimerToGetMap    = NULL;
+
+  DnsSb->Timer            = NULL;
+
+  DnsSb->IpVersion        = IpVersion;
+
+  //
+  // Create the timer used to time out the procedure which is used to
+  // get the default IP address.
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER,
+                  TPL_CALLBACK,
+                  NULL,
+                  NULL,
+                  &DnsSb->TimerToGetMap
+                  );
+  if (EFI_ERROR (Status)) {
+    FreePool (DnsSb);
+    return Status;
+  }
+
+  //
+  // Create the timer to retransmit packets.
+  //
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,
+                  TPL_CALLBACK,
+                  DnsOnTimerRetransmit,
+                  DnsSb,
+                  &DnsSb->Timer
+                  );
+  if (EFI_ERROR (Status)) {
+    if (DnsSb->TimerToGetMap != NULL) {
+      gBS->CloseEvent (DnsSb->TimerToGetMap);
+    }
+    FreePool (DnsSb);
+    return Status;
+  }
+
+  DnsSb->ConnectUdp = NULL;
+  DnsSb->ConnectUdp = UdpIoCreateIo (
+                        Controller,
+                        Image,
+                        DnsConfigNullUdp,
+                        DnsSb->IpVersion,
+                        NULL
+                        );
+  if (DnsSb->ConnectUdp == NULL) {
+    if (DnsSb->TimerToGetMap != NULL) {
+      gBS->CloseEvent (DnsSb->TimerToGetMap);
+    }
+    gBS->CloseEvent (DnsSb->Timer);
+    FreePool (DnsSb);
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Service = DnsSb;
+  return Status;
+}
+
+/**
+  Unloads an image.
+
+  @param  ImageHandle           Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS           The image has been unloaded.
+  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+DnsUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS  Status;
+
+  LIST_ENTRY                      *Entry;
+  DNS4_CACHE                      *ItemCache4;
+  DNS4_SERVER_IP                  *ItemServerIp4;
+  DNS6_CACHE                      *ItemCache6;
+  DNS6_SERVER_IP                  *ItemServerIp6;
+
+  ItemCache4    = NULL;
+  ItemServerIp4 = NULL;
+  ItemCache6    = NULL;
+  ItemServerIp6 = NULL;
+
+  //
+  // Disconnect the driver specified by ImageHandle
+  //
+  Status = NetLibDefaultUnload(ImageHandle);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Free mDriverData.
+  //
+  if (mDriverData != NULL) {
+    if (mDriverData->Timer != NULL) {
+      gBS->CloseEvent (mDriverData->Timer);
+    }
+
+    while (!IsListEmpty (&mDriverData->Dns4CacheList)) {
+      Entry = NetListRemoveHead (&mDriverData->Dns4CacheList);
+      ASSERT (Entry != NULL);
+      ItemCache4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
+      FreePool (ItemCache4->DnsCache.HostName);
+      FreePool (ItemCache4->DnsCache.IpAddress);
+      FreePool (ItemCache4);
+    }
+
+    while (!IsListEmpty (&mDriverData->Dns4ServerList)) {
+      Entry = NetListRemoveHead (&mDriverData->Dns4ServerList);
+      ASSERT (Entry != NULL);
+      ItemServerIp4 = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
+      FreePool (ItemServerIp4);
+    }
+
+    while (!IsListEmpty (&mDriverData->Dns6CacheList)) {
+      Entry = NetListRemoveHead (&mDriverData->Dns6CacheList);
+      ASSERT (Entry != NULL);
+      ItemCache6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
+      FreePool (ItemCache6->DnsCache.HostName);
+      FreePool (ItemCache6->DnsCache.IpAddress);
+      FreePool (ItemCache6);
+    }
+
+    while (!IsListEmpty (&mDriverData->Dns6ServerList)) {
+      Entry = NetListRemoveHead (&mDriverData->Dns6ServerList);
+      ASSERT (Entry != NULL);
+      ItemServerIp6 = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
+      FreePool (ItemServerIp6);
+    }
+
+    FreePool (mDriverData);
+  }
+
+  return Status;
+}
+
+/**
+  This is the declaration of an EFI image entry point. This entry point is
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+  both device drivers and bus drivers.
+
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param  SystemTable           A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+DnsDriverEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Install the Dns4 Driver Binding Protocol.
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gDns4DriverBinding,
+             ImageHandle,
+             &gDnsComponentName,
+             &gDnsComponentName2
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Install the Dns6 Driver Binding Protocol.
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gDns6DriverBinding,
+             NULL,
+             &gDnsComponentName,
+             &gDnsComponentName2
+             );
+  if (EFI_ERROR (Status)) {
+    goto Error1;
+  }
+
+  //
+  // Create the driver data structures.
+  //
+  mDriverData = AllocateZeroPool (sizeof (DNS_DRIVER_DATA));
+  if (mDriverData == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error2;
+  }
+
+  //
+  // Create the timer event to update DNS cache list.
+  //
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,
+                  TPL_CALLBACK,
+                  DnsOnTimerUpdate,
+                  NULL,
+                  &mDriverData->Timer
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Error3;
+  }
+
+  Status = gBS->SetTimer (mDriverData->Timer, TimerPeriodic, TICKS_PER_SECOND);
+  if (EFI_ERROR (Status)) {
+    goto Error4;
+  }
+
+  InitializeListHead (&mDriverData->Dns4CacheList);
+  InitializeListHead (&mDriverData->Dns4ServerList);
+  InitializeListHead (&mDriverData->Dns6CacheList);
+  InitializeListHead (&mDriverData->Dns6ServerList);
+
+  return Status;
+
+  Error4:
+    gBS->CloseEvent (mDriverData->Timer);
+
+  Error3:
+    FreePool (mDriverData);
+
+  Error2:
+     EfiLibUninstallDriverBindingComponentName2 (
+       &gDns6DriverBinding,
+       &gDnsComponentName,
+       &gDnsComponentName2
+       );
+
+  Error1:
+    EfiLibUninstallDriverBindingComponentName2 (
+      &gDns4DriverBinding,
+      &gDnsComponentName,
+      &gDnsComponentName2
+      );
+
+  return Status;
+}
+
+/**
+  Tests to see if this driver supports a given controller. If a child device is provided,
+  it further tests to see if this driver supports creating a handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the device specified by
+  ControllerHandle. Drivers will typically use the device path attached to
+  ControllerHandle and/or the services from the bus I/O abstraction attached to
+  ControllerHandle to determine if the driver supports ControllerHandle. This function
+  may be called many times during platform initialization. In order to reduce boot times, the tests
+  performed by this function must be very small, and take as little time as possible to execute. This
+  function must not change the state of any hardware devices, and this function must be aware that the
+  device specified by ControllerHandle may already be managed by the same driver or a
+  different driver. This function must match its calls to AllocatePages() with FreePages(),
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required
+  to guarantee the state of ControllerHandle is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter is not NULL, then
+                                   the bus driver must determine if the bus controller specified
+                                   by ControllerHandle and the child controller specified
+                                   by RemainingDevicePath are both supported by this
+                                   bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by the driver
+                                   specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by a different
+                                   driver or an application that requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+Dns4DriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Test for the Dns4ServiceBinding Protocol.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDns4ServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Test for the Udp4ServiceBinding Protocol.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiUdp4ServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+
+  return Status;
+}
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+     EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For a bus driver, if this parameter is NULL, then handles
+                                   for all the children of Controller are created by this driver.
+                                   If this parameter is not NULL and the first Device Path Node is
+                                   not the End of Device Path Node, then only the handle for the
+                                   child device specified by the first Device Path Node of
+                                   RemainingDevicePath is created by this driver.
+                                   If the first Device Path Node of RemainingDevicePath is
+                                   the End of Device Path Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
+  @retval Others                   The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+Dns4DriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  DNS_SERVICE            *DnsSb;
+  EFI_STATUS             Status;
+
+  Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4, &DnsSb);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ASSERT (DnsSb != NULL);
+
+  Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  //
+  // Install the Dns4ServiceBinding Protocol onto ControllerHandle.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ControllerHandle,
+                  &gEfiDns4ServiceBindingProtocolGuid,
+                  &DnsSb->ServiceBinding,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+  DnsDestroyService (DnsSb);
+
+  return Status;
+}
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been moved
+  into this common boot service. It is legal to call Stop() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+     same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+     Start() function, and the Start() function must have called OpenProtocol() on
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
+                                support a bus specific I/O protocol for the driver
+                                to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
+                                if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+Dns4DriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
+  )
+{
+  EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
+  DNS_SERVICE                                *DnsSb;
+  EFI_HANDLE                                 NicHandle;
+  EFI_STATUS                                 Status;
+  LIST_ENTRY                                 *List;
+  DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT    Context;
+
+  //
+  // DNS driver opens UDP child, So, Controller is a UDP
+  // child handle. Locate the Nic handle first. Then get the
+  // DNS private data back.
+  //
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
+
+  if (NicHandle == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->OpenProtocol (
+                  NicHandle,
+                  &gEfiDns4ServiceBindingProtocolGuid,
+                  (VOID **) &ServiceBinding,
+                  This->DriverBindingHandle,
+                  NicHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
+
+  if (!IsListEmpty (&DnsSb->Dns4ChildrenList)) {
+    //
+    // Destroy the Dns child instance in ChildHandleBuffer.
+    //
+    List = &DnsSb->Dns4ChildrenList;
+    Context.ServiceBinding    = ServiceBinding;
+    Context.NumberOfChildren  = NumberOfChildren;
+    Context.ChildHandleBuffer = ChildHandleBuffer;
+    Status = NetDestroyLinkList (
+               List,
+               DnsDestroyChildEntryInHandleBuffer,
+               &Context,
+               NULL
+               );
+  }
+
+  if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns4ChildrenList)) {
+    gBS->UninstallProtocolInterface (
+           NicHandle,
+           &gEfiDns4ServiceBindingProtocolGuid,
+           ServiceBinding
+           );
+
+    DnsDestroyService (DnsSb);
+
+    if (gDnsControllerNameTable != NULL) {
+      FreeUnicodeStringTable (gDnsControllerNameTable);
+      gDnsControllerNameTable = NULL;
+    }
+
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+  Tests to see if this driver supports a given controller. If a child device is provided,
+  it further tests to see if this driver supports creating a handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the device specified by
+  ControllerHandle. Drivers will typically use the device path attached to
+  ControllerHandle and/or the services from the bus I/O abstraction attached to
+  ControllerHandle to determine if the driver supports ControllerHandle. This function
+  may be called many times during platform initialization. In order to reduce boot times, the tests
+  performed by this function must be very small, and take as little time as possible to execute. This
+  function must not change the state of any hardware devices, and this function must be aware that the
+  device specified by ControllerHandle may already be managed by the same driver or a
+  different driver. This function must match its calls to AllocatePages() with FreePages(),
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required
+  to guarantee the state of ControllerHandle is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter is not NULL, then
+                                   the bus driver must determine if the bus controller specified
+                                   by ControllerHandle and the child controller specified
+                                   by RemainingDevicePath are both supported by this
+                                   bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by the driver
+                                   specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by a different
+                                   driver or an application that requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+Dns6DriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Test for the Dns6ServiceBinding Protocol
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDns6ServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Test for the Udp6ServiceBinding Protocol
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiUdp6ServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+
+  return Status;
+}
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+     EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For a bus driver, if this parameter is NULL, then handles
+                                   for all the children of Controller are created by this driver.
+                                   If this parameter is not NULL and the first Device Path Node is
+                                   not the End of Device Path Node, then only the handle for the
+                                   child device specified by the first Device Path Node of
+                                   RemainingDevicePath is created by this driver.
+                                   If the first Device Path Node of RemainingDevicePath is
+                                   the End of Device Path Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
+  @retval Others                   The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+Dns6DriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  DNS_SERVICE            *DnsSb;
+  EFI_STATUS             Status;
+
+  Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6, &DnsSb);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ASSERT (DnsSb != NULL);
+
+  Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  //
+  // Install the Dns6ServiceBinding Protocol onto ControllerHandle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ControllerHandle,
+                  &gEfiDns6ServiceBindingProtocolGuid,
+                  &DnsSb->ServiceBinding,
+                  NULL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+  DnsDestroyService (DnsSb);
+
+  return Status;
+}
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been moved
+  into this common boot service. It is legal to call Stop() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+     same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+     Start() function, and the Start() function must have called OpenProtocol() on
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
+                                support a bus specific I/O protocol for the driver
+                                to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
+                                if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+Dns6DriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
+  )
+{
+  EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
+  DNS_SERVICE                                *DnsSb;
+  EFI_HANDLE                                 NicHandle;
+  EFI_STATUS                                 Status;
+  LIST_ENTRY                                 *List;
+  DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT    Context;
+
+  //
+  // DNS driver opens UDP child, So, Controller is a UDP
+  // child handle. Locate the Nic handle first. Then get the
+  // DNS private data back.
+  //
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);
+
+  if (NicHandle == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->OpenProtocol (
+                  NicHandle,
+                  &gEfiDns6ServiceBindingProtocolGuid,
+                  (VOID **) &ServiceBinding,
+                  This->DriverBindingHandle,
+                  NicHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
+
+  if (!IsListEmpty (&DnsSb->Dns6ChildrenList)) {
+    //
+    // Destroy the Dns child instance in ChildHandleBuffer.
+    //
+    List = &DnsSb->Dns6ChildrenList;
+    Context.ServiceBinding    = ServiceBinding;
+    Context.NumberOfChildren  = NumberOfChildren;
+    Context.ChildHandleBuffer = ChildHandleBuffer;
+    Status = NetDestroyLinkList (
+               List,
+               DnsDestroyChildEntryInHandleBuffer,
+               &Context,
+               NULL
+               );
+  }
+
+  if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns6ChildrenList)) {
+    gBS->UninstallProtocolInterface (
+           NicHandle,
+           &gEfiDns6ServiceBindingProtocolGuid,
+           ServiceBinding
+           );
+
+    DnsDestroyService (DnsSb);
+
+    if (gDnsControllerNameTable != NULL) {
+      FreeUnicodeStringTable (gDnsControllerNameTable);
+      gDnsControllerNameTable = NULL;
+    }
+
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+  Creates a child handle and installs a protocol.
+
+  The CreateChild() function installs a protocol on ChildHandle.
+  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+  @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+  @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
+                         then a new handle is created. If it is a pointer to an existing UEFI handle,
+                         then the protocol is added to the existing UEFI handle.
+
+  @retval EFI_SUCCESS           The protocol was added to ChildHandle.
+  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
+                                the child
+  @retval other                 The child handle was not created
+
+**/
+EFI_STATUS
+EFIAPI
+Dns4ServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  )
+{
+  DNS_SERVICE               *DnsSb;
+  DNS_INSTANCE              *Instance;
+  EFI_STATUS                Status;
+  EFI_TPL                   OldTpl;
+  VOID                      *Udp4;
+
+  if ((This == NULL) || (ChildHandle == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DnsSb = DNS_SERVICE_FROM_THIS (This);
+
+  Status = DnsCreateInstance (DnsSb, &Instance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ASSERT (Instance != NULL);
+
+  //
+  // Install the DNS protocol onto ChildHandle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  ChildHandle,
+                  &gEfiDns4ProtocolGuid,
+                  &Instance->Dns4,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Instance->ChildHandle = *ChildHandle;
+
+  //
+  // Open the Udp4 protocol BY_CHILD.
+  //
+  Status = gBS->OpenProtocol (
+                  DnsSb->ConnectUdp->UdpHandle,
+                  &gEfiUdp4ProtocolGuid,
+                  (VOID **) &Udp4,
+                  gDns4DriverBinding.DriverBindingHandle,
+                  Instance->ChildHandle,
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+  if (EFI_ERROR (Status)) {
+    gBS->UninstallMultipleProtocolInterfaces (
+           Instance->ChildHandle,
+           &gEfiDns4ProtocolGuid,
+           &Instance->Dns4,
+           NULL
+           );
+
+    goto ON_ERROR;
+  }
+
+  //
+  // Open the Udp4 protocol by child.
+  //
+  Status = gBS->OpenProtocol (
+                  Instance->UdpIo->UdpHandle,
+                  &gEfiUdp4ProtocolGuid,
+                  (VOID **) &Udp4,
+                  gDns4DriverBinding.DriverBindingHandle,
+                  Instance->ChildHandle,
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // Close the Udp4 protocol.
+    //
+    gBS->CloseProtocol (
+           DnsSb->ConnectUdp->UdpHandle,
+           &gEfiUdp4ProtocolGuid,
+           gDns4DriverBinding.DriverBindingHandle,
+           *ChildHandle
+           );
+
+     gBS->UninstallMultipleProtocolInterfaces (
+            Instance->ChildHandle,
+            &gEfiDns4ProtocolGuid,
+            &Instance->Dns4,
+            NULL
+            );
+
+    goto ON_ERROR;
+  }
+
+  //
+  // Add it to the parent's child list.
+  //
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  InsertTailList (&DnsSb->Dns4ChildrenList, &Instance->Link);
+  DnsSb->Dns4ChildrenNum++;
+
+  gBS->RestoreTPL (OldTpl);
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  DnsDestroyInstance (Instance);
+  return Status;
+}
+
+/**
+  Destroys a child handle with a protocol installed on it.
+
+  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+  that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+  last protocol on ChildHandle, then ChildHandle is destroyed.
+
+  @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+  @param[in] ChildHandle Handle of the child to destroy
+
+  @retval EFI_SUCCESS           The protocol was removed from ChildHandle.
+  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
+  @retval EFI_INVALID_PARAMETER Child handle is NULL.
+  @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
+                                because its services are being used.
+  @retval other                 The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+Dns4ServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  )
+{
+  DNS_SERVICE               *DnsSb;
+  DNS_INSTANCE              *Instance;
+
+  EFI_DNS4_PROTOCOL         *Dns4;
+  EFI_STATUS                Status;
+  EFI_TPL                   OldTpl;
+
+  if ((This == NULL) || (ChildHandle == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Retrieve the private context data structures
+  //
+  Status = gBS->OpenProtocol (
+                  ChildHandle,
+                  &gEfiDns4ProtocolGuid,
+                  (VOID **) &Dns4,
+                  gDns4DriverBinding.DriverBindingHandle,
+                  ChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Instance  = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (Dns4);
+  DnsSb     = DNS_SERVICE_FROM_THIS (This);
+
+  if (Instance->Service != DnsSb) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Instance->InDestroy) {
+    return EFI_SUCCESS;
+  }
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  Instance->InDestroy = TRUE;
+
+  //
+  // Close the Udp4 protocol.
+  //
+  gBS->CloseProtocol (
+         DnsSb->ConnectUdp->UdpHandle,
+         &gEfiUdp4ProtocolGuid,
+         gDns4DriverBinding.DriverBindingHandle,
+         ChildHandle
+         );
+
+  gBS->CloseProtocol (
+         Instance->UdpIo->UdpHandle,
+         &gEfiUdp4ProtocolGuid,
+         gDns4DriverBinding.DriverBindingHandle,
+         ChildHandle
+         );
+
+  gBS->RestoreTPL (OldTpl);
+
+  //
+  // Uninstall the DNS protocol first to enable a top down destruction.
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  ChildHandle,
+                  &gEfiDns4ProtocolGuid,
+                  Dns4
+                  );
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  if (EFI_ERROR (Status)) {
+    Instance->InDestroy = FALSE;
+    gBS->RestoreTPL (OldTpl);
+    return Status;
+  }
+
+  RemoveEntryList (&Instance->Link);
+  DnsSb->Dns4ChildrenNum--;
+
+  gBS->RestoreTPL (OldTpl);
+
+  DnsDestroyInstance (Instance);
+  return EFI_SUCCESS;
+}
+
+/**
+  Creates a child handle and installs a protocol.
+
+  The CreateChild() function installs a protocol on ChildHandle.
+  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+  @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+  @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
+                         then a new handle is created. If it is a pointer to an existing UEFI handle,
+                         then the protocol is added to the existing UEFI handle.
+
+  @retval EFI_SUCCESS           The protocol was added to ChildHandle.
+  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
+                                the child
+  @retval other                 The child handle was not created
+
+**/
+EFI_STATUS
+EFIAPI
+Dns6ServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  )
+{
+  DNS_SERVICE               *DnsSb;
+  DNS_INSTANCE              *Instance;
+  EFI_STATUS                Status;
+  EFI_TPL                   OldTpl;
+  VOID                      *Udp6;
+
+  if ((This == NULL) || (ChildHandle == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DnsSb = DNS_SERVICE_FROM_THIS (This);
+
+  Status = DnsCreateInstance (DnsSb, &Instance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ASSERT (Instance != NULL);
+
+  //
+  // Install the DNS protocol onto ChildHandle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  ChildHandle,
+                  &gEfiDns6ProtocolGuid,
+                  &Instance->Dns6,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Instance->ChildHandle = *ChildHandle;
+
+  //
+  // Open the Udp6 protocol BY_CHILD.
+  //
+  Status = gBS->OpenProtocol (
+                  DnsSb->ConnectUdp->UdpHandle,
+                  &gEfiUdp6ProtocolGuid,
+                  (VOID **) &Udp6,
+                  gDns6DriverBinding.DriverBindingHandle,
+                  Instance->ChildHandle,
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+  if (EFI_ERROR (Status)) {
+    gBS->UninstallMultipleProtocolInterfaces (
+           Instance->ChildHandle,
+           &gEfiDns6ProtocolGuid,
+           &Instance->Dns6,
+           NULL
+           );
+
+    goto ON_ERROR;
+  }
+
+  //
+  // Open the Udp6 protocol by child.
+  //
+  Status = gBS->OpenProtocol (
+                  Instance->UdpIo->UdpHandle,
+                  &gEfiUdp6ProtocolGuid,
+                  (VOID **) &Udp6,
+                  gDns6DriverBinding.DriverBindingHandle,
+                  Instance->ChildHandle,
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // Close the Udp6 protocol.
+    //
+    gBS->CloseProtocol (
+           DnsSb->ConnectUdp->UdpHandle,
+           &gEfiUdp6ProtocolGuid,
+           gDns6DriverBinding.DriverBindingHandle,
+           *ChildHandle
+           );
+
+     gBS->UninstallMultipleProtocolInterfaces (
+            Instance->ChildHandle,
+            &gEfiDns6ProtocolGuid,
+            &Instance->Dns6,
+            NULL
+            );
+
+    goto ON_ERROR;
+  }
+
+  //
+  // Add it to the parent's child list.
+  //
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  InsertTailList (&DnsSb->Dns6ChildrenList, &Instance->Link);
+  DnsSb->Dns6ChildrenNum++;
+
+  gBS->RestoreTPL (OldTpl);
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  DnsDestroyInstance (Instance);
+  return Status;
+}
+
+/**
+  Destroys a child handle with a protocol installed on it.
+
+  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+  that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+  last protocol on ChildHandle, then ChildHandle is destroyed.
+
+  @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+  @param[in] ChildHandle Handle of the child to destroy
+
+  @retval EFI_SUCCESS           The protocol was removed from ChildHandle.
+  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
+  @retval EFI_INVALID_PARAMETER Child handle is NULL.
+  @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
+                                because its services are being used.
+  @retval other                 The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+Dns6ServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  )
+{
+  DNS_SERVICE               *DnsSb;
+  DNS_INSTANCE              *Instance;
+
+  EFI_DNS6_PROTOCOL         *Dns6;
+  EFI_STATUS                Status;
+  EFI_TPL                   OldTpl;
+
+  if ((This == NULL) || (ChildHandle == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Retrieve the private context data structures
+  //
+  Status = gBS->OpenProtocol (
+                  ChildHandle,
+                  &gEfiDns6ProtocolGuid,
+                  (VOID **) &Dns6,
+                  gDns6DriverBinding.DriverBindingHandle,
+                  ChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Instance  = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (Dns6);
+  DnsSb     = DNS_SERVICE_FROM_THIS (This);
+
+  if (Instance->Service != DnsSb) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Instance->InDestroy) {
+    return EFI_SUCCESS;
+  }
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  Instance->InDestroy = TRUE;
+
+  //
+  // Close the Udp6 protocol.
+  //
+  gBS->CloseProtocol (
+         DnsSb->ConnectUdp->UdpHandle,
+         &gEfiUdp6ProtocolGuid,
+         gDns6DriverBinding.DriverBindingHandle,
+         ChildHandle
+         );
+
+  gBS->CloseProtocol (
+         Instance->UdpIo->UdpHandle,
+         &gEfiUdp6ProtocolGuid,
+         gDns6DriverBinding.DriverBindingHandle,
+         ChildHandle
+         );
+
+  gBS->RestoreTPL (OldTpl);
+
+  //
+  // Uninstall the DNS protocol first to enable a top down destruction.
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  ChildHandle,
+                  &gEfiDns6ProtocolGuid,
+                  Dns6
+                  );
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  if (EFI_ERROR (Status)) {
+    Instance->InDestroy = FALSE;
+    gBS->RestoreTPL (OldTpl);
+    return Status;
+  }
+
+  RemoveEntryList (&Instance->Link);
+  DnsSb->Dns6ChildrenNum--;
+
+  gBS->RestoreTPL (OldTpl);
+
+  DnsDestroyInstance (Instance);
+  return EFI_SUCCESS;
+}
-- 
cgit