Home | History | Annotate | Download | only in DnsDxe
      1 /** @file
      2 The driver binding and service binding protocol for DnsDxe driver.
      3 
      4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DnsImpl.h"
     16 
     17 EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding = {
     18   Dns4DriverBindingSupported,
     19   Dns4DriverBindingStart,
     20   Dns4DriverBindingStop,
     21   DNS_VERSION,
     22   NULL,
     23   NULL
     24 };
     25 
     26 EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding = {
     27   Dns6DriverBindingSupported,
     28   Dns6DriverBindingStart,
     29   Dns6DriverBindingStop,
     30   DNS_VERSION,
     31   NULL,
     32   NULL
     33 };
     34 
     35 EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding = {
     36   Dns4ServiceBindingCreateChild,
     37   Dns4ServiceBindingDestroyChild
     38 };
     39 
     40 EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding = {
     41   Dns6ServiceBindingCreateChild,
     42   Dns6ServiceBindingDestroyChild
     43 };
     44 
     45 DNS_DRIVER_DATA          *mDriverData = NULL;
     46 
     47 /**
     48   Destroy the DNS instance and recycle the resources.
     49 
     50   @param[in]  Instance        The pointer to the DNS instance.
     51 
     52 **/
     53 VOID
     54 DnsDestroyInstance (
     55   IN DNS_INSTANCE         *Instance
     56   )
     57 {
     58   ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA));
     59 
     60   ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA));
     61 
     62   if (!NetMapIsEmpty (&Instance->Dns4TxTokens)) {
     63     Dns4InstanceCancelToken (Instance, NULL);
     64   }
     65 
     66   if (!NetMapIsEmpty (&Instance->Dns6TxTokens)) {
     67     Dns6InstanceCancelToken (Instance, NULL);
     68   }
     69 
     70   if (Instance->UdpIo!= NULL) {
     71     UdpIoFreeIo (Instance->UdpIo);
     72   }
     73 
     74   FreePool (Instance);
     75 }
     76 
     77 /**
     78   Create the DNS instance and initialize it.
     79 
     80   @param[in]  Service              The pointer to the DNS service.
     81   @param[out] Instance             The pointer to the DNS instance.
     82 
     83   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
     84   @retval EFI_SUCCESS            The DNS instance is created.
     85 
     86 **/
     87 EFI_STATUS
     88 DnsCreateInstance (
     89   IN  DNS_SERVICE         *Service,
     90   OUT DNS_INSTANCE        **Instance
     91   )
     92 {
     93   DNS_INSTANCE            *DnsIns;
     94 
     95   *Instance = NULL;
     96 
     97   DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE));
     98   if (DnsIns == NULL) {
     99     return EFI_OUT_OF_RESOURCES;
    100   }
    101 
    102   DnsIns->Signature = DNS_INSTANCE_SIGNATURE;
    103   InitializeListHead (&DnsIns->Link);
    104   DnsIns->State     = DNS_STATE_UNCONFIGED;
    105   DnsIns->InDestroy = FALSE;
    106   DnsIns->Service   = Service;
    107 
    108   if (Service->IpVersion == IP_VERSION_4) {
    109     CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4));
    110     NetMapInit (&DnsIns->Dns4TxTokens);
    111   } else {
    112     CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6));
    113     NetMapInit (&DnsIns->Dns6TxTokens);
    114   }
    115 
    116   DnsIns->UdpIo = UdpIoCreateIo (
    117                     Service->ControllerHandle, /// NicHandle
    118                     Service->ImageHandle,
    119                     DnsConfigNullUdp,
    120                     Service->IpVersion,
    121                     DnsIns
    122                     );
    123   if (DnsIns->UdpIo == NULL) {
    124     FreePool (DnsIns);
    125     return EFI_OUT_OF_RESOURCES;
    126   }
    127 
    128   *Instance = DnsIns;
    129 
    130   return EFI_SUCCESS;
    131 }
    132 
    133 /**
    134   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    135 
    136   @param[in]    Entry           The entry to be removed.
    137   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    138 
    139   @retval EFI_SUCCESS           The entry has been removed successfully.
    140   @retval Others                Fail to remove the entry.
    141 
    142 **/
    143 EFI_STATUS
    144 EFIAPI
    145 DnsDestroyChildEntryInHandleBuffer (
    146   IN LIST_ENTRY         *Entry,
    147   IN VOID               *Context
    148   )
    149 {
    150   DNS_INSTANCE                  *Instance;
    151   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    152   UINTN                         NumberOfChildren;
    153   EFI_HANDLE                    *ChildHandleBuffer;
    154 
    155   if (Entry == NULL || Context == NULL) {
    156     return EFI_INVALID_PARAMETER;
    157   }
    158 
    159   Instance = NET_LIST_USER_STRUCT_S (Entry, DNS_INSTANCE, Link, DNS_INSTANCE_SIGNATURE);
    160   ServiceBinding    = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
    161   NumberOfChildren  = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
    162   ChildHandleBuffer = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
    163 
    164   if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) {
    165     return EFI_SUCCESS;
    166   }
    167 
    168   return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
    169 }
    170 
    171 /**
    172   Config a NULL UDP that is used to keep the connection between UDP and DNS.
    173 
    174   Just leave the Udp child unconfigured. When UDP is unloaded,
    175     DNS will be informed with DriverBinding Stop.
    176 
    177   @param  UdpIo                  The UDP_IO to configure
    178   @param  Context                The opaque parameter to the callback
    179 
    180   @retval EFI_SUCCESS            It always return EFI_SUCCESS directly.
    181 
    182 **/
    183 EFI_STATUS
    184 EFIAPI
    185 DnsConfigNullUdp (
    186   IN UDP_IO                 *UdpIo,
    187   IN VOID                   *Context
    188   )
    189 {
    190   return EFI_SUCCESS;
    191 }
    192 
    193 /**
    194   Release all the resource used the DNS service binding instance.
    195 
    196   @param  DnsSb                The Dns service binding instance.
    197 
    198 **/
    199 VOID
    200 DnsDestroyService (
    201   IN DNS_SERVICE     *DnsSb
    202   )
    203 {
    204   UdpIoFreeIo (DnsSb->ConnectUdp);
    205 
    206   if (DnsSb->TimerToGetMap != NULL){
    207     gBS->CloseEvent (DnsSb->TimerToGetMap);
    208   }
    209 
    210   if (DnsSb->Timer != NULL){
    211     gBS->CloseEvent (DnsSb->Timer);
    212   }
    213 
    214   FreePool (DnsSb);
    215 }
    216 
    217 /**
    218   Create then initialize a Dns service binding instance.
    219 
    220   @param  Controller             The controller to install the DNS service
    221                                  binding on
    222   @param  Image                  The driver binding image of the DNS driver
    223   @param  IpVersion              IpVersion for this service
    224   @param  Service                The variable to receive the created service
    225                                  binding instance.
    226 
    227   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource to create the instance.
    228   @retval EFI_DEVICE_ERROR       Failed to create a NULL UDP port to keep
    229                                  connection  with UDP.
    230   @retval EFI_SUCCESS            The service instance is created for the
    231                                  controller.
    232 
    233 **/
    234 EFI_STATUS
    235 DnsCreateService (
    236   IN     EFI_HANDLE            Controller,
    237   IN     EFI_HANDLE            Image,
    238   IN     UINT8                 IpVersion,
    239      OUT DNS_SERVICE           **Service
    240   )
    241 {
    242   EFI_STATUS             Status;
    243   DNS_SERVICE            *DnsSb;
    244 
    245   Status    = EFI_SUCCESS;
    246   DnsSb     = NULL;
    247 
    248   *Service  = NULL;
    249 
    250   DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE));
    251   if (DnsSb == NULL) {
    252     return EFI_OUT_OF_RESOURCES;
    253   }
    254 
    255   DnsSb->Signature = DNS_SERVICE_SIGNATURE;
    256 
    257   if (IpVersion == IP_VERSION_4) {
    258     DnsSb->ServiceBinding = mDns4ServiceBinding;
    259   } else {
    260     DnsSb->ServiceBinding = mDns6ServiceBinding;
    261   }
    262 
    263   DnsSb->Dns4ChildrenNum = 0;
    264   InitializeListHead (&DnsSb->Dns4ChildrenList);
    265 
    266   DnsSb->Dns6ChildrenNum = 0;
    267   InitializeListHead (&DnsSb->Dns6ChildrenList);
    268 
    269   DnsSb->ControllerHandle = Controller;
    270   DnsSb->ImageHandle      = Image;
    271 
    272   DnsSb->TimerToGetMap    = NULL;
    273 
    274   DnsSb->Timer            = NULL;
    275 
    276   DnsSb->IpVersion        = IpVersion;
    277 
    278   //
    279   // Create the timer used to time out the procedure which is used to
    280   // get the default IP address.
    281   //
    282   if (DnsSb->IpVersion == IP_VERSION_4) {
    283     Status = gBS->CreateEvent (
    284                     EVT_TIMER,
    285                     TPL_CALLBACK,
    286                     NULL,
    287                     NULL,
    288                     &DnsSb->TimerToGetMap
    289                     );
    290     if (EFI_ERROR (Status)) {
    291       FreePool (DnsSb);
    292       return Status;
    293     }
    294   }
    295 
    296   //
    297   // Create the timer to retransmit packets.
    298   //
    299   Status = gBS->CreateEvent (
    300                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    301                   TPL_CALLBACK,
    302                   DnsOnTimerRetransmit,
    303                   DnsSb,
    304                   &DnsSb->Timer
    305                   );
    306   if (EFI_ERROR (Status)) {
    307     if (DnsSb->TimerToGetMap != NULL) {
    308       gBS->CloseEvent (DnsSb->TimerToGetMap);
    309     }
    310     FreePool (DnsSb);
    311     return Status;
    312   }
    313 
    314   DnsSb->ConnectUdp = NULL;
    315   DnsSb->ConnectUdp = UdpIoCreateIo (
    316                         Controller,
    317                         Image,
    318                         DnsConfigNullUdp,
    319                         DnsSb->IpVersion,
    320                         NULL
    321                         );
    322   if (DnsSb->ConnectUdp == NULL) {
    323     if (DnsSb->TimerToGetMap != NULL) {
    324       gBS->CloseEvent (DnsSb->TimerToGetMap);
    325     }
    326     gBS->CloseEvent (DnsSb->Timer);
    327     FreePool (DnsSb);
    328     return EFI_DEVICE_ERROR;
    329   }
    330 
    331   *Service = DnsSb;
    332   return Status;
    333 }
    334 
    335 /**
    336   Unloads an image.
    337 
    338   @param  ImageHandle           Handle that identifies the image to be unloaded.
    339 
    340   @retval EFI_SUCCESS           The image has been unloaded.
    341   @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
    342 
    343 **/
    344 EFI_STATUS
    345 EFIAPI
    346 DnsUnload (
    347   IN EFI_HANDLE  ImageHandle
    348   )
    349 {
    350   EFI_STATUS  Status;
    351 
    352   LIST_ENTRY                      *Entry;
    353   DNS4_CACHE                      *ItemCache4;
    354   DNS4_SERVER_IP                  *ItemServerIp4;
    355   DNS6_CACHE                      *ItemCache6;
    356   DNS6_SERVER_IP                  *ItemServerIp6;
    357 
    358   ItemCache4    = NULL;
    359   ItemServerIp4 = NULL;
    360   ItemCache6    = NULL;
    361   ItemServerIp6 = NULL;
    362 
    363   //
    364   // Disconnect the driver specified by ImageHandle
    365   //
    366   Status = NetLibDefaultUnload(ImageHandle);
    367   if (EFI_ERROR (Status)) {
    368     return Status;
    369   }
    370 
    371   //
    372   // Free mDriverData.
    373   //
    374   if (mDriverData != NULL) {
    375     if (mDriverData->Timer != NULL) {
    376       gBS->CloseEvent (mDriverData->Timer);
    377     }
    378 
    379     while (!IsListEmpty (&mDriverData->Dns4CacheList)) {
    380       Entry = NetListRemoveHead (&mDriverData->Dns4CacheList);
    381       ItemCache4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    382       if (ItemCache4->DnsCache.HostName != NULL) {
    383         FreePool (ItemCache4->DnsCache.HostName);
    384       }
    385       if (ItemCache4->DnsCache.IpAddress != NULL) {
    386         FreePool (ItemCache4->DnsCache.IpAddress);
    387       }
    388       FreePool (ItemCache4);
    389     }
    390 
    391     while (!IsListEmpty (&mDriverData->Dns4ServerList)) {
    392       Entry = NetListRemoveHead (&mDriverData->Dns4ServerList);
    393       ItemServerIp4 = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
    394       FreePool (ItemServerIp4);
    395     }
    396 
    397     while (!IsListEmpty (&mDriverData->Dns6CacheList)) {
    398       Entry = NetListRemoveHead (&mDriverData->Dns6CacheList);
    399       ItemCache6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
    400       if (ItemCache6->DnsCache.HostName != NULL) {
    401         FreePool (ItemCache6->DnsCache.HostName);
    402       }
    403       if (ItemCache6->DnsCache.IpAddress != NULL) {
    404         FreePool (ItemCache6->DnsCache.IpAddress);
    405       }
    406       FreePool (ItemCache6);
    407     }
    408 
    409     while (!IsListEmpty (&mDriverData->Dns6ServerList)) {
    410       Entry = NetListRemoveHead (&mDriverData->Dns6ServerList);
    411       ItemServerIp6 = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
    412       FreePool (ItemServerIp6);
    413     }
    414 
    415     FreePool (mDriverData);
    416   }
    417 
    418   return Status;
    419 }
    420 
    421 /**
    422   This is the declaration of an EFI image entry point. This entry point is
    423   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
    424   both device drivers and bus drivers.
    425 
    426   @param  ImageHandle           The firmware allocated handle for the UEFI image.
    427   @param  SystemTable           A pointer to the EFI System Table.
    428 
    429   @retval EFI_SUCCESS           The operation completed successfully.
    430   @retval Others                An unexpected error occurred.
    431 **/
    432 EFI_STATUS
    433 EFIAPI
    434 DnsDriverEntryPoint (
    435   IN EFI_HANDLE        ImageHandle,
    436   IN EFI_SYSTEM_TABLE  *SystemTable
    437   )
    438 {
    439   EFI_STATUS  Status;
    440 
    441   Status = EFI_SUCCESS;
    442 
    443   //
    444   // Install the Dns4 Driver Binding Protocol.
    445   //
    446   Status = EfiLibInstallDriverBindingComponentName2 (
    447              ImageHandle,
    448              SystemTable,
    449              &gDns4DriverBinding,
    450              ImageHandle,
    451              &gDnsComponentName,
    452              &gDnsComponentName2
    453              );
    454   if (EFI_ERROR (Status)) {
    455     return Status;
    456   }
    457 
    458   //
    459   // Install the Dns6 Driver Binding Protocol.
    460   //
    461   Status = EfiLibInstallDriverBindingComponentName2 (
    462              ImageHandle,
    463              SystemTable,
    464              &gDns6DriverBinding,
    465              NULL,
    466              &gDnsComponentName,
    467              &gDnsComponentName2
    468              );
    469   if (EFI_ERROR (Status)) {
    470     goto Error1;
    471   }
    472 
    473   //
    474   // Create the driver data structures.
    475   //
    476   mDriverData = AllocateZeroPool (sizeof (DNS_DRIVER_DATA));
    477   if (mDriverData == NULL) {
    478     Status = EFI_OUT_OF_RESOURCES;
    479     goto Error2;
    480   }
    481 
    482   //
    483   // Create the timer event to update DNS cache list.
    484   //
    485   Status = gBS->CreateEvent (
    486                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    487                   TPL_CALLBACK,
    488                   DnsOnTimerUpdate,
    489                   NULL,
    490                   &mDriverData->Timer
    491                   );
    492   if (EFI_ERROR (Status)) {
    493     goto Error3;
    494   }
    495 
    496   Status = gBS->SetTimer (mDriverData->Timer, TimerPeriodic, TICKS_PER_SECOND);
    497   if (EFI_ERROR (Status)) {
    498     goto Error4;
    499   }
    500 
    501   InitializeListHead (&mDriverData->Dns4CacheList);
    502   InitializeListHead (&mDriverData->Dns4ServerList);
    503   InitializeListHead (&mDriverData->Dns6CacheList);
    504   InitializeListHead (&mDriverData->Dns6ServerList);
    505 
    506   return Status;
    507 
    508   Error4:
    509     gBS->CloseEvent (mDriverData->Timer);
    510 
    511   Error3:
    512     FreePool (mDriverData);
    513 
    514   Error2:
    515      gBS->UninstallMultipleProtocolInterfaces (
    516            gDns6DriverBinding.DriverBindingHandle,
    517            &gEfiDriverBindingProtocolGuid,
    518            &gDns6DriverBinding,
    519            &gEfiComponentName2ProtocolGuid,
    520            &gDnsComponentName2,
    521            &gEfiComponentNameProtocolGuid,
    522            &gDnsComponentName,
    523            NULL
    524            );
    525 
    526   Error1:
    527     gBS->UninstallMultipleProtocolInterfaces (
    528            ImageHandle,
    529            &gEfiDriverBindingProtocolGuid,
    530            &gDns4DriverBinding,
    531            &gEfiComponentName2ProtocolGuid,
    532            &gDnsComponentName2,
    533            &gEfiComponentNameProtocolGuid,
    534            &gDnsComponentName,
    535            NULL
    536            );
    537 
    538   return Status;
    539 }
    540 
    541 /**
    542   Tests to see if this driver supports a given controller. If a child device is provided,
    543   it further tests to see if this driver supports creating a handle for the specified child device.
    544 
    545   This function checks to see if the driver specified by This supports the device specified by
    546   ControllerHandle. Drivers will typically use the device path attached to
    547   ControllerHandle and/or the services from the bus I/O abstraction attached to
    548   ControllerHandle to determine if the driver supports ControllerHandle. This function
    549   may be called many times during platform initialization. In order to reduce boot times, the tests
    550   performed by this function must be very small, and take as little time as possible to execute. This
    551   function must not change the state of any hardware devices, and this function must be aware that the
    552   device specified by ControllerHandle may already be managed by the same driver or a
    553   different driver. This function must match its calls to AllocatePages() with FreePages(),
    554   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
    555   Because ControllerHandle may have been previously started by the same driver, if a protocol is
    556   already in the opened state, then it must not be closed with CloseProtocol(). This is required
    557   to guarantee the state of ControllerHandle is not modified by this function.
    558 
    559   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    560   @param[in]  ControllerHandle     The handle of the controller to test. This handle
    561                                    must support a protocol interface that supplies
    562                                    an I/O abstraction to the driver.
    563   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    564                                    parameter is ignored by device drivers, and is optional for bus
    565                                    drivers. For bus drivers, if this parameter is not NULL, then
    566                                    the bus driver must determine if the bus controller specified
    567                                    by ControllerHandle and the child controller specified
    568                                    by RemainingDevicePath are both supported by this
    569                                    bus driver.
    570 
    571   @retval EFI_SUCCESS              The device specified by ControllerHandle and
    572                                    RemainingDevicePath is supported by the driver specified by This.
    573   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
    574                                    RemainingDevicePath is already being managed by the driver
    575                                    specified by This.
    576   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
    577                                    RemainingDevicePath is already being managed by a different
    578                                    driver or an application that requires exclusive access.
    579                                    Currently not implemented.
    580   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
    581                                    RemainingDevicePath is not supported by the driver specified by This.
    582 **/
    583 EFI_STATUS
    584 EFIAPI
    585 Dns4DriverBindingSupported (
    586   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    587   IN EFI_HANDLE                   ControllerHandle,
    588   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    589   )
    590 {
    591   EFI_STATUS  Status;
    592 
    593   //
    594   // Test for the Dns4ServiceBinding Protocol.
    595   //
    596   Status = gBS->OpenProtocol (
    597                   ControllerHandle,
    598                   &gEfiDns4ServiceBindingProtocolGuid,
    599                   NULL,
    600                   This->DriverBindingHandle,
    601                   ControllerHandle,
    602                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    603                   );
    604   if (!EFI_ERROR (Status)) {
    605     return EFI_ALREADY_STARTED;
    606   }
    607 
    608   //
    609   // Test for the Udp4ServiceBinding Protocol.
    610   //
    611   Status = gBS->OpenProtocol (
    612                   ControllerHandle,
    613                   &gEfiUdp4ServiceBindingProtocolGuid,
    614                   NULL,
    615                   This->DriverBindingHandle,
    616                   ControllerHandle,
    617                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    618                   );
    619 
    620   return Status;
    621 }
    622 
    623 /**
    624   Starts a device controller or a bus controller.
    625 
    626   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    627   As a result, much of the error checking on the parameters to Start() has been moved into this
    628   common boot service. It is legal to call Start() from other locations,
    629   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    630   1. ControllerHandle must be a valid EFI_HANDLE.
    631   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    632      EFI_DEVICE_PATH_PROTOCOL.
    633   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    634      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    635 
    636   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    637   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    638                                    must support a protocol interface that supplies
    639                                    an I/O abstraction to the driver.
    640   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    641                                    parameter is ignored by device drivers, and is optional for bus
    642                                    drivers. For a bus driver, if this parameter is NULL, then handles
    643                                    for all the children of Controller are created by this driver.
    644                                    If this parameter is not NULL and the first Device Path Node is
    645                                    not the End of Device Path Node, then only the handle for the
    646                                    child device specified by the first Device Path Node of
    647                                    RemainingDevicePath is created by this driver.
    648                                    If the first Device Path Node of RemainingDevicePath is
    649                                    the End of Device Path Node, no child handle is created by this
    650                                    driver.
    651 
    652   @retval EFI_SUCCESS              The device was started.
    653   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
    654   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    655   @retval Others                   The driver failded to start the device.
    656 
    657 **/
    658 EFI_STATUS
    659 EFIAPI
    660 Dns4DriverBindingStart (
    661   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    662   IN EFI_HANDLE                   ControllerHandle,
    663   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    664   )
    665 {
    666   DNS_SERVICE            *DnsSb;
    667   EFI_STATUS             Status;
    668 
    669   Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4, &DnsSb);
    670   if (EFI_ERROR (Status)) {
    671     return Status;
    672   }
    673 
    674   ASSERT (DnsSb != NULL);
    675 
    676   Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
    677   if (EFI_ERROR (Status)) {
    678     goto ON_ERROR;
    679   }
    680 
    681   //
    682   // Install the Dns4ServiceBinding Protocol onto ControllerHandle.
    683   //
    684   Status = gBS->InstallMultipleProtocolInterfaces (
    685                   &ControllerHandle,
    686                   &gEfiDns4ServiceBindingProtocolGuid,
    687                   &DnsSb->ServiceBinding,
    688                   NULL
    689                   );
    690   if (EFI_ERROR (Status)) {
    691     goto ON_ERROR;
    692   }
    693 
    694   return EFI_SUCCESS;
    695 
    696 ON_ERROR:
    697   DnsDestroyService (DnsSb);
    698 
    699   return Status;
    700 }
    701 
    702 /**
    703   Stops a device controller or a bus controller.
    704 
    705   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
    706   As a result, much of the error checking on the parameters to Stop() has been moved
    707   into this common boot service. It is legal to call Stop() from other locations,
    708   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    709   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    710      same driver's Start() function.
    711   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    712      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    713      Start() function, and the Start() function must have called OpenProtocol() on
    714      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    715 
    716   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    717   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    718                                 support a bus specific I/O protocol for the driver
    719                                 to use to stop the device.
    720   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    721   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    722                                 if NumberOfChildren is 0.
    723 
    724   @retval EFI_SUCCESS           The device was stopped.
    725   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    726 
    727 **/
    728 EFI_STATUS
    729 EFIAPI
    730 Dns4DriverBindingStop (
    731   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    732   IN EFI_HANDLE                   ControllerHandle,
    733   IN UINTN                        NumberOfChildren,
    734   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
    735   )
    736 {
    737   EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
    738   DNS_SERVICE                                *DnsSb;
    739   EFI_HANDLE                                 NicHandle;
    740   EFI_STATUS                                 Status;
    741   LIST_ENTRY                                 *List;
    742   DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT    Context;
    743 
    744   //
    745   // DNS driver opens UDP child, So, Controller is a UDP
    746   // child handle. Locate the Nic handle first. Then get the
    747   // DNS private data back.
    748   //
    749   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
    750 
    751   if (NicHandle == NULL) {
    752     return EFI_SUCCESS;
    753   }
    754 
    755   Status = gBS->OpenProtocol (
    756                   NicHandle,
    757                   &gEfiDns4ServiceBindingProtocolGuid,
    758                   (VOID **) &ServiceBinding,
    759                   This->DriverBindingHandle,
    760                   NicHandle,
    761                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    762                   );
    763   if (EFI_ERROR (Status)) {
    764     return EFI_DEVICE_ERROR;
    765   }
    766 
    767   DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
    768 
    769   if (!IsListEmpty (&DnsSb->Dns4ChildrenList)) {
    770     //
    771     // Destroy the Dns child instance in ChildHandleBuffer.
    772     //
    773     List = &DnsSb->Dns4ChildrenList;
    774     Context.ServiceBinding    = ServiceBinding;
    775     Context.NumberOfChildren  = NumberOfChildren;
    776     Context.ChildHandleBuffer = ChildHandleBuffer;
    777     Status = NetDestroyLinkList (
    778                List,
    779                DnsDestroyChildEntryInHandleBuffer,
    780                &Context,
    781                NULL
    782                );
    783   }
    784 
    785   if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns4ChildrenList)) {
    786     gBS->UninstallProtocolInterface (
    787            NicHandle,
    788            &gEfiDns4ServiceBindingProtocolGuid,
    789            ServiceBinding
    790            );
    791 
    792     DnsDestroyService (DnsSb);
    793 
    794     if (gDnsControllerNameTable != NULL) {
    795       FreeUnicodeStringTable (gDnsControllerNameTable);
    796       gDnsControllerNameTable = NULL;
    797     }
    798 
    799     Status = EFI_SUCCESS;
    800   }
    801 
    802   return Status;
    803 }
    804 
    805 /**
    806   Tests to see if this driver supports a given controller. If a child device is provided,
    807   it further tests to see if this driver supports creating a handle for the specified child device.
    808 
    809   This function checks to see if the driver specified by This supports the device specified by
    810   ControllerHandle. Drivers will typically use the device path attached to
    811   ControllerHandle and/or the services from the bus I/O abstraction attached to
    812   ControllerHandle to determine if the driver supports ControllerHandle. This function
    813   may be called many times during platform initialization. In order to reduce boot times, the tests
    814   performed by this function must be very small, and take as little time as possible to execute. This
    815   function must not change the state of any hardware devices, and this function must be aware that the
    816   device specified by ControllerHandle may already be managed by the same driver or a
    817   different driver. This function must match its calls to AllocatePages() with FreePages(),
    818   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
    819   Because ControllerHandle may have been previously started by the same driver, if a protocol is
    820   already in the opened state, then it must not be closed with CloseProtocol(). This is required
    821   to guarantee the state of ControllerHandle is not modified by this function.
    822 
    823   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    824   @param[in]  ControllerHandle     The handle of the controller to test. This handle
    825                                    must support a protocol interface that supplies
    826                                    an I/O abstraction to the driver.
    827   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    828                                    parameter is ignored by device drivers, and is optional for bus
    829                                    drivers. For bus drivers, if this parameter is not NULL, then
    830                                    the bus driver must determine if the bus controller specified
    831                                    by ControllerHandle and the child controller specified
    832                                    by RemainingDevicePath are both supported by this
    833                                    bus driver.
    834 
    835   @retval EFI_SUCCESS              The device specified by ControllerHandle and
    836                                    RemainingDevicePath is supported by the driver specified by This.
    837   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
    838                                    RemainingDevicePath is already being managed by the driver
    839                                    specified by This.
    840   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
    841                                    RemainingDevicePath is already being managed by a different
    842                                    driver or an application that requires exclusive access.
    843                                    Currently not implemented.
    844   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
    845                                    RemainingDevicePath is not supported by the driver specified by This.
    846 **/
    847 EFI_STATUS
    848 EFIAPI
    849 Dns6DriverBindingSupported (
    850   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    851   IN EFI_HANDLE                   ControllerHandle,
    852   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    853   )
    854 {
    855   EFI_STATUS  Status;
    856 
    857   //
    858   // Test for the Dns6ServiceBinding Protocol
    859   //
    860   Status = gBS->OpenProtocol (
    861                   ControllerHandle,
    862                   &gEfiDns6ServiceBindingProtocolGuid,
    863                   NULL,
    864                   This->DriverBindingHandle,
    865                   ControllerHandle,
    866                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    867                   );
    868   if (!EFI_ERROR (Status)) {
    869     return EFI_ALREADY_STARTED;
    870   }
    871 
    872   //
    873   // Test for the Udp6ServiceBinding Protocol
    874   //
    875   Status = gBS->OpenProtocol (
    876                   ControllerHandle,
    877                   &gEfiUdp6ServiceBindingProtocolGuid,
    878                   NULL,
    879                   This->DriverBindingHandle,
    880                   ControllerHandle,
    881                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    882                   );
    883 
    884   return Status;
    885 }
    886 
    887 /**
    888   Starts a device controller or a bus controller.
    889 
    890   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    891   As a result, much of the error checking on the parameters to Start() has been moved into this
    892   common boot service. It is legal to call Start() from other locations,
    893   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    894   1. ControllerHandle must be a valid EFI_HANDLE.
    895   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    896      EFI_DEVICE_PATH_PROTOCOL.
    897   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    898      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    899 
    900   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    901   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    902                                    must support a protocol interface that supplies
    903                                    an I/O abstraction to the driver.
    904   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    905                                    parameter is ignored by device drivers, and is optional for bus
    906                                    drivers. For a bus driver, if this parameter is NULL, then handles
    907                                    for all the children of Controller are created by this driver.
    908                                    If this parameter is not NULL and the first Device Path Node is
    909                                    not the End of Device Path Node, then only the handle for the
    910                                    child device specified by the first Device Path Node of
    911                                    RemainingDevicePath is created by this driver.
    912                                    If the first Device Path Node of RemainingDevicePath is
    913                                    the End of Device Path Node, no child handle is created by this
    914                                    driver.
    915 
    916   @retval EFI_SUCCESS              The device was started.
    917   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
    918   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    919   @retval Others                   The driver failded to start the device.
    920 
    921 **/
    922 EFI_STATUS
    923 EFIAPI
    924 Dns6DriverBindingStart (
    925   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    926   IN EFI_HANDLE                   ControllerHandle,
    927   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    928   )
    929 {
    930   DNS_SERVICE            *DnsSb;
    931   EFI_STATUS             Status;
    932 
    933   Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6, &DnsSb);
    934   if (EFI_ERROR (Status)) {
    935     return Status;
    936   }
    937 
    938   ASSERT (DnsSb != NULL);
    939 
    940   Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
    941   if (EFI_ERROR (Status)) {
    942     goto ON_ERROR;
    943   }
    944 
    945   //
    946   // Install the Dns6ServiceBinding Protocol onto ControllerHandle
    947   //
    948   Status = gBS->InstallMultipleProtocolInterfaces (
    949                   &ControllerHandle,
    950                   &gEfiDns6ServiceBindingProtocolGuid,
    951                   &DnsSb->ServiceBinding,
    952                   NULL
    953                   );
    954 
    955   if (EFI_ERROR (Status)) {
    956     goto ON_ERROR;
    957   }
    958 
    959   return EFI_SUCCESS;
    960 
    961 ON_ERROR:
    962   DnsDestroyService (DnsSb);
    963 
    964   return Status;
    965 }
    966 
    967 /**
    968   Stops a device controller or a bus controller.
    969 
    970   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
    971   As a result, much of the error checking on the parameters to Stop() has been moved
    972   into this common boot service. It is legal to call Stop() from other locations,
    973   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    974   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    975      same driver's Start() function.
    976   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    977      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    978      Start() function, and the Start() function must have called OpenProtocol() on
    979      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    980 
    981   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    982   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    983                                 support a bus specific I/O protocol for the driver
    984                                 to use to stop the device.
    985   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    986   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    987                                 if NumberOfChildren is 0.
    988 
    989   @retval EFI_SUCCESS           The device was stopped.
    990   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    991 
    992 **/
    993 EFI_STATUS
    994 EFIAPI
    995 Dns6DriverBindingStop (
    996   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    997   IN EFI_HANDLE                   ControllerHandle,
    998   IN UINTN                        NumberOfChildren,
    999   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
   1000   )
   1001 {
   1002   EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
   1003   DNS_SERVICE                                *DnsSb;
   1004   EFI_HANDLE                                 NicHandle;
   1005   EFI_STATUS                                 Status;
   1006   LIST_ENTRY                                 *List;
   1007   DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT    Context;
   1008 
   1009   //
   1010   // DNS driver opens UDP child, So, Controller is a UDP
   1011   // child handle. Locate the Nic handle first. Then get the
   1012   // DNS private data back.
   1013   //
   1014   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);
   1015 
   1016   if (NicHandle == NULL) {
   1017     return EFI_SUCCESS;
   1018   }
   1019 
   1020   Status = gBS->OpenProtocol (
   1021                   NicHandle,
   1022                   &gEfiDns6ServiceBindingProtocolGuid,
   1023                   (VOID **) &ServiceBinding,
   1024                   This->DriverBindingHandle,
   1025                   NicHandle,
   1026                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1027                   );
   1028   if (EFI_ERROR (Status)) {
   1029     return EFI_DEVICE_ERROR;
   1030   }
   1031 
   1032   DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
   1033 
   1034   if (!IsListEmpty (&DnsSb->Dns6ChildrenList)) {
   1035     //
   1036     // Destroy the Dns child instance in ChildHandleBuffer.
   1037     //
   1038     List = &DnsSb->Dns6ChildrenList;
   1039     Context.ServiceBinding    = ServiceBinding;
   1040     Context.NumberOfChildren  = NumberOfChildren;
   1041     Context.ChildHandleBuffer = ChildHandleBuffer;
   1042     Status = NetDestroyLinkList (
   1043                List,
   1044                DnsDestroyChildEntryInHandleBuffer,
   1045                &Context,
   1046                NULL
   1047                );
   1048   }
   1049 
   1050   if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns6ChildrenList)) {
   1051     gBS->UninstallProtocolInterface (
   1052            NicHandle,
   1053            &gEfiDns6ServiceBindingProtocolGuid,
   1054            ServiceBinding
   1055            );
   1056 
   1057     DnsDestroyService (DnsSb);
   1058 
   1059     if (gDnsControllerNameTable != NULL) {
   1060       FreeUnicodeStringTable (gDnsControllerNameTable);
   1061       gDnsControllerNameTable = NULL;
   1062     }
   1063 
   1064     Status = EFI_SUCCESS;
   1065   }
   1066 
   1067   return Status;
   1068 }
   1069 
   1070 /**
   1071   Creates a child handle and installs a protocol.
   1072 
   1073   The CreateChild() function installs a protocol on ChildHandle.
   1074   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
   1075   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
   1076 
   1077   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
   1078   @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
   1079                          then a new handle is created. If it is a pointer to an existing UEFI handle,
   1080                          then the protocol is added to the existing UEFI handle.
   1081 
   1082   @retval EFI_SUCCES            The protocol was added to ChildHandle.
   1083   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
   1084   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
   1085                                 the child
   1086   @retval other                 The child handle was not created
   1087 
   1088 **/
   1089 EFI_STATUS
   1090 EFIAPI
   1091 Dns4ServiceBindingCreateChild (
   1092   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
   1093   IN EFI_HANDLE                    *ChildHandle
   1094   )
   1095 {
   1096   DNS_SERVICE               *DnsSb;
   1097   DNS_INSTANCE              *Instance;
   1098   EFI_STATUS                Status;
   1099   EFI_TPL                   OldTpl;
   1100   VOID                      *Udp4;
   1101 
   1102   if ((This == NULL) || (ChildHandle == NULL)) {
   1103     return EFI_INVALID_PARAMETER;
   1104   }
   1105 
   1106   DnsSb = DNS_SERVICE_FROM_THIS (This);
   1107 
   1108   Status = DnsCreateInstance (DnsSb, &Instance);
   1109   if (EFI_ERROR (Status)) {
   1110     return Status;
   1111   }
   1112   ASSERT (Instance != NULL);
   1113 
   1114   //
   1115   // Install the DNS protocol onto ChildHandle
   1116   //
   1117   Status = gBS->InstallMultipleProtocolInterfaces (
   1118                   ChildHandle,
   1119                   &gEfiDns4ProtocolGuid,
   1120                   &Instance->Dns4,
   1121                   NULL
   1122                   );
   1123   if (EFI_ERROR (Status)) {
   1124     goto ON_ERROR;
   1125   }
   1126 
   1127   Instance->ChildHandle = *ChildHandle;
   1128 
   1129   //
   1130   // Open the Udp4 protocol BY_CHILD.
   1131   //
   1132   Status = gBS->OpenProtocol (
   1133                   DnsSb->ConnectUdp->UdpHandle,
   1134                   &gEfiUdp4ProtocolGuid,
   1135                   (VOID **) &Udp4,
   1136                   gDns4DriverBinding.DriverBindingHandle,
   1137                   Instance->ChildHandle,
   1138                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1139                   );
   1140   if (EFI_ERROR (Status)) {
   1141     gBS->UninstallMultipleProtocolInterfaces (
   1142            Instance->ChildHandle,
   1143            &gEfiDns4ProtocolGuid,
   1144            &Instance->Dns4,
   1145            NULL
   1146            );
   1147 
   1148     goto ON_ERROR;
   1149   }
   1150 
   1151   //
   1152   // Open the Udp4 protocol by child.
   1153   //
   1154   Status = gBS->OpenProtocol (
   1155                   Instance->UdpIo->UdpHandle,
   1156                   &gEfiUdp4ProtocolGuid,
   1157                   (VOID **) &Udp4,
   1158                   gDns4DriverBinding.DriverBindingHandle,
   1159                   Instance->ChildHandle,
   1160                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1161                   );
   1162   if (EFI_ERROR (Status)) {
   1163     //
   1164     // Close the Udp4 protocol.
   1165     //
   1166     gBS->CloseProtocol (
   1167            DnsSb->ConnectUdp->UdpHandle,
   1168            &gEfiUdp4ProtocolGuid,
   1169            gDns4DriverBinding.DriverBindingHandle,
   1170            ChildHandle
   1171            );
   1172 
   1173      gBS->UninstallMultipleProtocolInterfaces (
   1174             Instance->ChildHandle,
   1175             &gEfiDns4ProtocolGuid,
   1176             &Instance->Dns4,
   1177             NULL
   1178             );
   1179 
   1180     goto ON_ERROR;
   1181   }
   1182 
   1183   //
   1184   // Add it to the parent's child list.
   1185   //
   1186   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1187 
   1188   InsertTailList (&DnsSb->Dns4ChildrenList, &Instance->Link);
   1189   DnsSb->Dns4ChildrenNum++;
   1190 
   1191   gBS->RestoreTPL (OldTpl);
   1192 
   1193   return EFI_SUCCESS;
   1194 
   1195 ON_ERROR:
   1196 
   1197   DnsDestroyInstance (Instance);
   1198   return Status;
   1199 }
   1200 
   1201 /**
   1202   Destroys a child handle with a protocol installed on it.
   1203 
   1204   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
   1205   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
   1206   last protocol on ChildHandle, then ChildHandle is destroyed.
   1207 
   1208   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
   1209   @param[in] ChildHandle Handle of the child to destroy
   1210 
   1211   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
   1212   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
   1213   @retval EFI_INVALID_PARAMETER Child handle is NULL.
   1214   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
   1215                                 because its services are being used.
   1216   @retval other                 The child handle was not destroyed
   1217 
   1218 **/
   1219 EFI_STATUS
   1220 EFIAPI
   1221 Dns4ServiceBindingDestroyChild (
   1222   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
   1223   IN EFI_HANDLE                    ChildHandle
   1224   )
   1225 {
   1226   DNS_SERVICE               *DnsSb;
   1227   DNS_INSTANCE              *Instance;
   1228 
   1229   EFI_DNS4_PROTOCOL         *Dns4;
   1230   EFI_STATUS                Status;
   1231   EFI_TPL                   OldTpl;
   1232 
   1233   if ((This == NULL) || (ChildHandle == NULL)) {
   1234     return EFI_INVALID_PARAMETER;
   1235   }
   1236 
   1237   //
   1238   // Retrieve the private context data structures
   1239   //
   1240   Status = gBS->OpenProtocol (
   1241                   ChildHandle,
   1242                   &gEfiDns4ProtocolGuid,
   1243                   (VOID **) &Dns4,
   1244                   gDns4DriverBinding.DriverBindingHandle,
   1245                   ChildHandle,
   1246                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1247                   );
   1248 
   1249   if (EFI_ERROR (Status)) {
   1250     return EFI_UNSUPPORTED;
   1251   }
   1252 
   1253   Instance  = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (Dns4);
   1254   DnsSb     = DNS_SERVICE_FROM_THIS (This);
   1255 
   1256   if (Instance->Service != DnsSb) {
   1257     return EFI_INVALID_PARAMETER;
   1258   }
   1259 
   1260   if (Instance->InDestroy) {
   1261     return EFI_SUCCESS;
   1262   }
   1263 
   1264   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1265 
   1266   Instance->InDestroy = TRUE;
   1267 
   1268   //
   1269   // Close the Udp4 protocol.
   1270   //
   1271   gBS->CloseProtocol (
   1272          DnsSb->ConnectUdp->UdpHandle,
   1273          &gEfiUdp4ProtocolGuid,
   1274          gDns4DriverBinding.DriverBindingHandle,
   1275          ChildHandle
   1276          );
   1277 
   1278   gBS->CloseProtocol (
   1279          Instance->UdpIo->UdpHandle,
   1280          &gEfiUdp4ProtocolGuid,
   1281          gDns4DriverBinding.DriverBindingHandle,
   1282          ChildHandle
   1283          );
   1284 
   1285   gBS->RestoreTPL (OldTpl);
   1286 
   1287   //
   1288   // Uninstall the DNS protocol first to enable a top down destruction.
   1289   //
   1290   Status = gBS->UninstallProtocolInterface (
   1291                   ChildHandle,
   1292                   &gEfiDns4ProtocolGuid,
   1293                   Dns4
   1294                   );
   1295 
   1296   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1297 
   1298   if (EFI_ERROR (Status)) {
   1299     Instance->InDestroy = FALSE;
   1300     gBS->RestoreTPL (OldTpl);
   1301     return Status;
   1302   }
   1303 
   1304   RemoveEntryList (&Instance->Link);
   1305   DnsSb->Dns4ChildrenNum--;
   1306 
   1307   gBS->RestoreTPL (OldTpl);
   1308 
   1309   DnsDestroyInstance (Instance);
   1310   return EFI_SUCCESS;
   1311 }
   1312 
   1313 /**
   1314   Creates a child handle and installs a protocol.
   1315 
   1316   The CreateChild() function installs a protocol on ChildHandle.
   1317   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
   1318   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
   1319 
   1320   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
   1321   @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
   1322                          then a new handle is created. If it is a pointer to an existing UEFI handle,
   1323                          then the protocol is added to the existing UEFI handle.
   1324 
   1325   @retval EFI_SUCCES            The protocol was added to ChildHandle.
   1326   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
   1327   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
   1328                                 the child
   1329   @retval other                 The child handle was not created
   1330 
   1331 **/
   1332 EFI_STATUS
   1333 EFIAPI
   1334 Dns6ServiceBindingCreateChild (
   1335   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
   1336   IN EFI_HANDLE                    *ChildHandle
   1337   )
   1338 {
   1339   DNS_SERVICE               *DnsSb;
   1340   DNS_INSTANCE              *Instance;
   1341   EFI_STATUS                Status;
   1342   EFI_TPL                   OldTpl;
   1343   VOID                      *Udp6;
   1344 
   1345   if ((This == NULL) || (ChildHandle == NULL)) {
   1346     return EFI_INVALID_PARAMETER;
   1347   }
   1348 
   1349   DnsSb = DNS_SERVICE_FROM_THIS (This);
   1350 
   1351   Status = DnsCreateInstance (DnsSb, &Instance);
   1352   if (EFI_ERROR (Status)) {
   1353     return Status;
   1354   }
   1355   ASSERT (Instance != NULL);
   1356 
   1357   //
   1358   // Install the DNS protocol onto ChildHandle
   1359   //
   1360   Status = gBS->InstallMultipleProtocolInterfaces (
   1361                   ChildHandle,
   1362                   &gEfiDns6ProtocolGuid,
   1363                   &Instance->Dns6,
   1364                   NULL
   1365                   );
   1366   if (EFI_ERROR (Status)) {
   1367     goto ON_ERROR;
   1368   }
   1369 
   1370   Instance->ChildHandle = *ChildHandle;
   1371 
   1372   //
   1373   // Open the Udp6 protocol BY_CHILD.
   1374   //
   1375   Status = gBS->OpenProtocol (
   1376                   DnsSb->ConnectUdp->UdpHandle,
   1377                   &gEfiUdp6ProtocolGuid,
   1378                   (VOID **) &Udp6,
   1379                   gDns6DriverBinding.DriverBindingHandle,
   1380                   Instance->ChildHandle,
   1381                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1382                   );
   1383   if (EFI_ERROR (Status)) {
   1384     gBS->UninstallMultipleProtocolInterfaces (
   1385            Instance->ChildHandle,
   1386            &gEfiDns6ProtocolGuid,
   1387            &Instance->Dns6,
   1388            NULL
   1389            );
   1390 
   1391     goto ON_ERROR;
   1392   }
   1393 
   1394   //
   1395   // Open the Udp6 protocol by child.
   1396   //
   1397   Status = gBS->OpenProtocol (
   1398                   Instance->UdpIo->UdpHandle,
   1399                   &gEfiUdp6ProtocolGuid,
   1400                   (VOID **) &Udp6,
   1401                   gDns6DriverBinding.DriverBindingHandle,
   1402                   Instance->ChildHandle,
   1403                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1404                   );
   1405   if (EFI_ERROR (Status)) {
   1406     //
   1407     // Close the Udp6 protocol.
   1408     //
   1409     gBS->CloseProtocol (
   1410            DnsSb->ConnectUdp->UdpHandle,
   1411            &gEfiUdp6ProtocolGuid,
   1412            gDns6DriverBinding.DriverBindingHandle,
   1413            ChildHandle
   1414            );
   1415 
   1416      gBS->UninstallMultipleProtocolInterfaces (
   1417             Instance->ChildHandle,
   1418             &gEfiDns6ProtocolGuid,
   1419             &Instance->Dns6,
   1420             NULL
   1421             );
   1422 
   1423     goto ON_ERROR;
   1424   }
   1425 
   1426   //
   1427   // Add it to the parent's child list.
   1428   //
   1429   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1430 
   1431   InsertTailList (&DnsSb->Dns6ChildrenList, &Instance->Link);
   1432   DnsSb->Dns6ChildrenNum++;
   1433 
   1434   gBS->RestoreTPL (OldTpl);
   1435 
   1436   return EFI_SUCCESS;
   1437 
   1438 ON_ERROR:
   1439 
   1440   DnsDestroyInstance (Instance);
   1441   return Status;
   1442 }
   1443 
   1444 /**
   1445   Destroys a child handle with a protocol installed on it.
   1446 
   1447   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
   1448   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
   1449   last protocol on ChildHandle, then ChildHandle is destroyed.
   1450 
   1451   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
   1452   @param[in] ChildHandle Handle of the child to destroy
   1453 
   1454   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
   1455   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
   1456   @retval EFI_INVALID_PARAMETER Child handle is NULL.
   1457   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
   1458                                 because its services are being used.
   1459   @retval other                 The child handle was not destroyed
   1460 
   1461 **/
   1462 EFI_STATUS
   1463 EFIAPI
   1464 Dns6ServiceBindingDestroyChild (
   1465   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
   1466   IN EFI_HANDLE                    ChildHandle
   1467   )
   1468 {
   1469   DNS_SERVICE               *DnsSb;
   1470   DNS_INSTANCE              *Instance;
   1471 
   1472   EFI_DNS6_PROTOCOL         *Dns6;
   1473   EFI_STATUS                Status;
   1474   EFI_TPL                   OldTpl;
   1475 
   1476   if ((This == NULL) || (ChildHandle == NULL)) {
   1477     return EFI_INVALID_PARAMETER;
   1478   }
   1479 
   1480   //
   1481   // Retrieve the private context data structures
   1482   //
   1483   Status = gBS->OpenProtocol (
   1484                   ChildHandle,
   1485                   &gEfiDns6ProtocolGuid,
   1486                   (VOID **) &Dns6,
   1487                   gDns6DriverBinding.DriverBindingHandle,
   1488                   ChildHandle,
   1489                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1490                   );
   1491 
   1492   if (EFI_ERROR (Status)) {
   1493     return EFI_UNSUPPORTED;
   1494   }
   1495 
   1496   Instance  = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (Dns6);
   1497   DnsSb     = DNS_SERVICE_FROM_THIS (This);
   1498 
   1499   if (Instance->Service != DnsSb) {
   1500     return EFI_INVALID_PARAMETER;
   1501   }
   1502 
   1503   if (Instance->InDestroy) {
   1504     return EFI_SUCCESS;
   1505   }
   1506 
   1507   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1508 
   1509   Instance->InDestroy = TRUE;
   1510 
   1511   //
   1512   // Close the Udp6 protocol.
   1513   //
   1514   gBS->CloseProtocol (
   1515          DnsSb->ConnectUdp->UdpHandle,
   1516          &gEfiUdp6ProtocolGuid,
   1517          gDns6DriverBinding.DriverBindingHandle,
   1518          ChildHandle
   1519          );
   1520 
   1521   gBS->CloseProtocol (
   1522          Instance->UdpIo->UdpHandle,
   1523          &gEfiUdp6ProtocolGuid,
   1524          gDns6DriverBinding.DriverBindingHandle,
   1525          ChildHandle
   1526          );
   1527 
   1528   gBS->RestoreTPL (OldTpl);
   1529 
   1530   //
   1531   // Uninstall the DNS protocol first to enable a top down destruction.
   1532   //
   1533   Status = gBS->UninstallProtocolInterface (
   1534                   ChildHandle,
   1535                   &gEfiDns6ProtocolGuid,
   1536                   Dns6
   1537                   );
   1538 
   1539   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1540 
   1541   if (EFI_ERROR (Status)) {
   1542     Instance->InDestroy = FALSE;
   1543     gBS->RestoreTPL (OldTpl);
   1544     return Status;
   1545   }
   1546 
   1547   RemoveEntryList (&Instance->Link);
   1548   DnsSb->Dns6ChildrenNum--;
   1549 
   1550   gBS->RestoreTPL (OldTpl);
   1551 
   1552   DnsDestroyInstance (Instance);
   1553   return EFI_SUCCESS;
   1554 }
   1555