Home | History | Annotate | Download | only in Dhcp4Dxe
      1 /** @file
      2 
      3 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 **/
     13 
     14 #include "Dhcp4Impl.h"
     15 #include "Dhcp4Driver.h"
     16 
     17 EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {
     18   Dhcp4DriverBindingSupported,
     19   Dhcp4DriverBindingStart,
     20   Dhcp4DriverBindingStop,
     21   0xa,
     22   NULL,
     23   NULL
     24 };
     25 
     26 EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplate = {
     27   Dhcp4ServiceBindingCreateChild,
     28   Dhcp4ServiceBindingDestroyChild
     29 };
     30 
     31 /**
     32   This is the declaration of an EFI image entry point. This entry point is
     33   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
     34   both device drivers and bus drivers.
     35 
     36   Entry point of the DHCP driver to install various protocols.
     37 
     38   @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
     39   @param[in]  SystemTable           A pointer to the EFI System Table.
     40 
     41   @retval EFI_SUCCESS           The operation completed successfully.
     42   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     43 
     44 **/
     45 EFI_STATUS
     46 EFIAPI
     47 Dhcp4DriverEntryPoint (
     48   IN EFI_HANDLE             ImageHandle,
     49   IN EFI_SYSTEM_TABLE       *SystemTable
     50   )
     51 {
     52   return EfiLibInstallDriverBindingComponentName2 (
     53            ImageHandle,
     54            SystemTable,
     55            &gDhcp4DriverBinding,
     56            ImageHandle,
     57            &gDhcp4ComponentName,
     58            &gDhcp4ComponentName2
     59            );
     60 }
     61 
     62 
     63 /**
     64   Test to see if this driver supports ControllerHandle. This service
     65   is called by the EFI boot service ConnectController(). In
     66   order to make drivers as small as possible, there are a few calling
     67   restrictions for this service. ConnectController() must
     68   follow these calling restrictions. If any other agent wishes to call
     69   Supported() it must also follow these calling restrictions.
     70 
     71   @param[in]  This                Protocol instance pointer.
     72   @param[in]  ControllerHandle    Handle of device to test
     73   @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
     74                                   device to start.
     75 
     76   @retval EFI_SUCCESS         This driver supports this device
     77   @retval EFI_ALREADY_STARTED This driver is already running on this device
     78   @retval other               This driver does not support this device
     79 
     80 **/
     81 EFI_STATUS
     82 EFIAPI
     83 Dhcp4DriverBindingSupported (
     84   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     85   IN EFI_HANDLE                   ControllerHandle,
     86   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     87   )
     88 {
     89   EFI_STATUS  Status;
     90 
     91   Status = gBS->OpenProtocol (
     92                   ControllerHandle,
     93                   &gEfiUdp4ServiceBindingProtocolGuid,
     94                   NULL,
     95                   This->DriverBindingHandle,
     96                   ControllerHandle,
     97                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
     98                   );
     99 
    100   return Status;
    101 }
    102 
    103 
    104 
    105 /**
    106   Configure the default UDP child to receive all the DHCP traffics
    107   on this network interface.
    108 
    109   @param[in]  UdpIo                  The UDP IO to configure
    110   @param[in]  Context                The context to the function
    111 
    112   @retval EFI_SUCCESS            The UDP IO is successfully configured.
    113   @retval Others                 Failed to configure the UDP child.
    114 
    115 **/
    116 EFI_STATUS
    117 EFIAPI
    118 DhcpConfigUdpIo (
    119   IN UDP_IO                 *UdpIo,
    120   IN VOID                   *Context
    121   )
    122 {
    123   EFI_UDP4_CONFIG_DATA      UdpConfigData;
    124 
    125   UdpConfigData.AcceptBroadcast           = TRUE;
    126   UdpConfigData.AcceptPromiscuous         = FALSE;
    127   UdpConfigData.AcceptAnyPort             = FALSE;
    128   UdpConfigData.AllowDuplicatePort        = TRUE;
    129   UdpConfigData.TypeOfService             = 0;
    130   UdpConfigData.TimeToLive                = 64;
    131   UdpConfigData.DoNotFragment             = FALSE;
    132   UdpConfigData.ReceiveTimeout            = 0;
    133   UdpConfigData.TransmitTimeout           = 0;
    134 
    135   UdpConfigData.UseDefaultAddress         = FALSE;
    136   UdpConfigData.StationPort               = DHCP_CLIENT_PORT;
    137   UdpConfigData.RemotePort                = DHCP_SERVER_PORT;
    138 
    139   ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
    140   ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    141   ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
    142 
    143   return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData);;
    144 }
    145 
    146 
    147 
    148 /**
    149   Destroy the DHCP service. The Dhcp4 service may be partly initialized,
    150   or partly destroyed. If a resource is destroyed, it is marked as so in
    151   case the destroy failed and being called again later.
    152 
    153   @param[in]  DhcpSb                 The DHCP service instance to destroy.
    154 
    155   @retval EFI_SUCCESS            Always return success.
    156 
    157 **/
    158 EFI_STATUS
    159 Dhcp4CloseService (
    160   IN DHCP_SERVICE           *DhcpSb
    161   )
    162 {
    163   DhcpCleanLease (DhcpSb);
    164 
    165   if (DhcpSb->UdpIo != NULL) {
    166     UdpIoFreeIo (DhcpSb->UdpIo);
    167     DhcpSb->UdpIo = NULL;
    168   }
    169 
    170   if (DhcpSb->Timer != NULL) {
    171     gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);
    172     gBS->CloseEvent (DhcpSb->Timer);
    173 
    174     DhcpSb->Timer = NULL;
    175   }
    176 
    177   return EFI_SUCCESS;
    178 }
    179 
    180 
    181 
    182 /**
    183   Create a new DHCP service binding instance for the controller.
    184 
    185   @param[in]  Controller             The controller to install DHCP service binding
    186                                      protocol onto
    187   @param[in]  ImageHandle            The driver's image handle
    188   @param[out] Service                The variable to receive the created DHCP service
    189                                      instance.
    190 
    191   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource .
    192   @retval EFI_SUCCESS            The DHCP service instance is created.
    193   @retval other                  Other error occurs.
    194 
    195 **/
    196 EFI_STATUS
    197 Dhcp4CreateService (
    198   IN  EFI_HANDLE            Controller,
    199   IN  EFI_HANDLE            ImageHandle,
    200   OUT DHCP_SERVICE          **Service
    201   )
    202 {
    203   DHCP_SERVICE              *DhcpSb;
    204   EFI_STATUS                Status;
    205 
    206   *Service  = NULL;
    207   DhcpSb    = AllocateZeroPool (sizeof (DHCP_SERVICE));
    208 
    209   if (DhcpSb == NULL) {
    210     return EFI_OUT_OF_RESOURCES;
    211   }
    212 
    213   DhcpSb->Signature       = DHCP_SERVICE_SIGNATURE;
    214   DhcpSb->ServiceState    = DHCP_UNCONFIGED;
    215   DhcpSb->Controller      = Controller;
    216   DhcpSb->Image           = ImageHandle;
    217   InitializeListHead (&DhcpSb->Children);
    218   DhcpSb->DhcpState       = Dhcp4Stopped;
    219   DhcpSb->Xid             = NET_RANDOM (NetRandomInitSeed ());
    220   CopyMem (
    221     &DhcpSb->ServiceBinding,
    222     &mDhcp4ServiceBindingTemplate,
    223     sizeof (EFI_SERVICE_BINDING_PROTOCOL)
    224     );
    225   //
    226   // Create various resources, UdpIo, Timer, and get Mac address
    227   //
    228   Status = gBS->CreateEvent (
    229                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    230                   TPL_CALLBACK,
    231                   DhcpOnTimerTick,
    232                   DhcpSb,
    233                   &DhcpSb->Timer
    234                   );
    235 
    236   if (EFI_ERROR (Status)) {
    237     goto ON_ERROR;
    238   }
    239 
    240   DhcpSb->UdpIo = UdpIoCreateIo (
    241                     Controller,
    242                     ImageHandle,
    243                     DhcpConfigUdpIo,
    244                     UDP_IO_UDP4_VERSION,
    245                     NULL
    246                     );
    247 
    248   if (DhcpSb->UdpIo == NULL) {
    249     Status = EFI_OUT_OF_RESOURCES;
    250     goto ON_ERROR;
    251   }
    252 
    253   DhcpSb->HwLen  = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;
    254   DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;
    255   CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));
    256 
    257   *Service       = DhcpSb;
    258   return EFI_SUCCESS;
    259 
    260 ON_ERROR:
    261   Dhcp4CloseService (DhcpSb);
    262   FreePool (DhcpSb);
    263 
    264   return Status;
    265 }
    266 
    267 
    268 /**
    269   Start this driver on ControllerHandle. This service is called by the
    270   EFI boot service ConnectController(). In order to make
    271   drivers as small as possible, there are a few calling restrictions for
    272   this service. ConnectController() must follow these
    273   calling restrictions. If any other agent wishes to call Start() it
    274   must also follow these calling restrictions.
    275 
    276   @param[in]  This                 Protocol instance pointer.
    277   @param[in]  ControllerHandle     Handle of device to bind driver to
    278   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
    279                                    device to start.
    280 
    281   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    282   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    283   @retval other                This driver does not support this device
    284 
    285 **/
    286 EFI_STATUS
    287 EFIAPI
    288 Dhcp4DriverBindingStart (
    289   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    290   IN EFI_HANDLE                   ControllerHandle,
    291   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    292   )
    293 {
    294   DHCP_SERVICE              *DhcpSb;
    295   EFI_STATUS                Status;
    296 
    297   //
    298   // First: test for the DHCP4 Protocol
    299   //
    300   Status = gBS->OpenProtocol (
    301                   ControllerHandle,
    302                   &gEfiDhcp4ServiceBindingProtocolGuid,
    303                   NULL,
    304                   This->DriverBindingHandle,
    305                   ControllerHandle,
    306                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    307                   );
    308 
    309   if (Status == EFI_SUCCESS) {
    310     return EFI_ALREADY_STARTED;
    311   }
    312 
    313   Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
    314 
    315   if (EFI_ERROR (Status)) {
    316     return Status;
    317   }
    318   ASSERT (DhcpSb != NULL);
    319 
    320   //
    321   // Start the receiving
    322   //
    323   Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);
    324 
    325   if (EFI_ERROR (Status)) {
    326     goto ON_ERROR;
    327   }
    328   Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
    329 
    330   if (EFI_ERROR (Status)) {
    331     goto ON_ERROR;
    332   }
    333 
    334   //
    335   // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
    336   //
    337   Status = gBS->InstallMultipleProtocolInterfaces (
    338                   &ControllerHandle,
    339                   &gEfiDhcp4ServiceBindingProtocolGuid,
    340                   &DhcpSb->ServiceBinding,
    341                   NULL
    342                   );
    343 
    344   if (EFI_ERROR (Status)) {
    345     goto ON_ERROR;
    346   }
    347 
    348   return Status;
    349 
    350 ON_ERROR:
    351   Dhcp4CloseService (DhcpSb);
    352   FreePool (DhcpSb);
    353   return Status;
    354 }
    355 
    356 /**
    357   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    358 
    359   @param[in]    Entry           The entry to be removed.
    360   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    361 
    362   @retval EFI_SUCCESS           The entry has been removed successfully.
    363   @retval Others                Fail to remove the entry.
    364 
    365 **/
    366 EFI_STATUS
    367 EFIAPI
    368 Dhcp4DestroyChildEntry (
    369   IN LIST_ENTRY         *Entry,
    370   IN VOID               *Context
    371   )
    372 {
    373   DHCP_PROTOCOL                    *Instance;
    374   EFI_SERVICE_BINDING_PROTOCOL     *ServiceBinding;
    375 
    376   if (Entry == NULL || Context == NULL) {
    377     return EFI_INVALID_PARAMETER;
    378   }
    379 
    380   Instance = NET_LIST_USER_STRUCT_S (Entry, DHCP_PROTOCOL, Link, DHCP_PROTOCOL_SIGNATURE);
    381   ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;
    382 
    383   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
    384 }
    385 
    386 
    387 /**
    388   Stop this driver on ControllerHandle. This service is called by the
    389   EFI boot service DisconnectController(). In order to
    390   make drivers as small as possible, there are a few calling
    391   restrictions for this service. DisconnectController()
    392   must follow these calling restrictions. If any other agent wishes
    393   to call Stop() it must also follow these calling restrictions.
    394 
    395   @param[in]  This              Protocol instance pointer.
    396   @param[in]  ControllerHandle  Handle of device to stop driver on
    397   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    398                                 children is zero stop the entire bus driver.
    399   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
    400 
    401   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    402   @retval other             This driver was not removed from this device
    403 
    404 **/
    405 EFI_STATUS
    406 EFIAPI
    407 Dhcp4DriverBindingStop (
    408   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    409   IN  EFI_HANDLE                   ControllerHandle,
    410   IN  UINTN                        NumberOfChildren,
    411   IN  EFI_HANDLE                   *ChildHandleBuffer
    412   )
    413 {
    414   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    415   DHCP_SERVICE                  *DhcpSb;
    416   EFI_HANDLE                    NicHandle;
    417   EFI_STATUS                    Status;
    418   LIST_ENTRY                    *List;
    419   UINTN                         ListLength;
    420 
    421   //
    422   // DHCP driver opens UDP child, So, the ControllerHandle is the
    423   // UDP child handle. locate the Nic handle first.
    424   //
    425   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
    426 
    427   if (NicHandle == NULL) {
    428     return EFI_SUCCESS;
    429   }
    430 
    431    Status = gBS->OpenProtocol (
    432                   NicHandle,
    433                   &gEfiDhcp4ServiceBindingProtocolGuid,
    434                   (VOID **) &ServiceBinding,
    435                   This->DriverBindingHandle,
    436                   NicHandle,
    437                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    438                   );
    439 
    440   if (EFI_ERROR (Status)) {
    441     return EFI_DEVICE_ERROR;
    442   }
    443 
    444   DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);
    445   if (!IsListEmpty (&DhcpSb->Children)) {
    446     //
    447     // Destroy all the children instances before destory the service.
    448     //
    449     List = &DhcpSb->Children;
    450     Status = NetDestroyLinkList (
    451                List,
    452                Dhcp4DestroyChildEntry,
    453                ServiceBinding,
    454                &ListLength
    455                );
    456     if (EFI_ERROR (Status) || ListLength != 0) {
    457       Status = EFI_DEVICE_ERROR;
    458     }
    459   }
    460 
    461   if (NumberOfChildren == 0 && !IsListEmpty (&DhcpSb->Children)) {
    462     Status = EFI_DEVICE_ERROR;
    463   }
    464 
    465   if (NumberOfChildren == 0 && IsListEmpty (&DhcpSb->Children)) {
    466     //
    467     // Destroy the service itself if no child instance left.
    468     //
    469     DhcpSb->ServiceState = DHCP_DESTROY;
    470 
    471     gBS->UninstallProtocolInterface (
    472            NicHandle,
    473            &gEfiDhcp4ServiceBindingProtocolGuid,
    474            ServiceBinding
    475            );
    476 
    477     Dhcp4CloseService (DhcpSb);
    478 
    479     if (gDhcpControllerNameTable != NULL) {
    480       FreeUnicodeStringTable (gDhcpControllerNameTable);
    481       gDhcpControllerNameTable = NULL;
    482     }
    483     FreePool (DhcpSb);
    484 
    485     Status = EFI_SUCCESS;
    486   }
    487 
    488   return Status;
    489 }
    490 
    491 
    492 /**
    493   Initialize a new DHCP instance.
    494 
    495   @param  DhcpSb                 The dhcp service instance
    496   @param  Instance               The dhcp instance to initialize
    497 
    498 **/
    499 VOID
    500 DhcpInitProtocol (
    501   IN     DHCP_SERVICE           *DhcpSb,
    502   IN OUT DHCP_PROTOCOL          *Instance
    503   )
    504 {
    505   Instance->Signature         = DHCP_PROTOCOL_SIGNATURE;
    506   CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));
    507   InitializeListHead (&Instance->Link);
    508   Instance->Handle            = NULL;
    509   Instance->Service           = DhcpSb;
    510   Instance->InDestroy         = FALSE;
    511   Instance->CompletionEvent   = NULL;
    512   Instance->RenewRebindEvent  = NULL;
    513   Instance->Token             = NULL;
    514   Instance->UdpIo             = NULL;
    515   Instance->ElaspedTime       = 0;
    516   NetbufQueInit (&Instance->ResponseQueue);
    517 }
    518 
    519 
    520 /**
    521   Creates a child handle and installs a protocol.
    522 
    523   The CreateChild() function installs a protocol on ChildHandle.
    524   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
    525   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
    526 
    527   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    528   @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,
    529                       then a new handle is created. If it is a pointer to an existing UEFI handle,
    530                       then the protocol is added to the existing UEFI handle.
    531 
    532   @retval EFI_SUCCES            The protocol was added to ChildHandle.
    533   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
    534   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
    535                                 the child
    536   @retval other                 The child handle was not created
    537 
    538 **/
    539 EFI_STATUS
    540 EFIAPI
    541 Dhcp4ServiceBindingCreateChild (
    542   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
    543   IN EFI_HANDLE                    *ChildHandle
    544   )
    545 {
    546   DHCP_SERVICE              *DhcpSb;
    547   DHCP_PROTOCOL             *Instance;
    548   EFI_STATUS                Status;
    549   EFI_TPL                   OldTpl;
    550   VOID                      *Udp4;
    551 
    552   if ((This == NULL) || (ChildHandle == NULL)) {
    553     return EFI_INVALID_PARAMETER;
    554   }
    555 
    556   Instance = AllocatePool (sizeof (*Instance));
    557 
    558   if (Instance == NULL) {
    559     return EFI_OUT_OF_RESOURCES;
    560   }
    561 
    562   DhcpSb = DHCP_SERVICE_FROM_THIS (This);
    563   DhcpInitProtocol (DhcpSb, Instance);
    564 
    565   //
    566   // Install DHCP4 onto ChildHandle
    567   //
    568   Status = gBS->InstallMultipleProtocolInterfaces (
    569                   ChildHandle,
    570                   &gEfiDhcp4ProtocolGuid,
    571                   &Instance->Dhcp4Protocol,
    572                   NULL
    573                   );
    574 
    575   if (EFI_ERROR (Status)) {
    576     FreePool (Instance);
    577     return Status;
    578   }
    579 
    580   Instance->Handle  = *ChildHandle;
    581 
    582   //
    583   // Open the Udp4 protocol BY_CHILD.
    584   //
    585   Status = gBS->OpenProtocol (
    586                   DhcpSb->UdpIo->UdpHandle,
    587                   &gEfiUdp4ProtocolGuid,
    588                   (VOID **) &Udp4,
    589                   gDhcp4DriverBinding.DriverBindingHandle,
    590                   Instance->Handle,
    591                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    592                   );
    593   if (EFI_ERROR (Status)) {
    594     gBS->UninstallMultipleProtocolInterfaces (
    595            Instance->Handle,
    596            &gEfiDhcp4ProtocolGuid,
    597            &Instance->Dhcp4Protocol,
    598            NULL
    599            );
    600 
    601     FreePool (Instance);
    602     return Status;
    603   }
    604 
    605   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    606 
    607   InsertTailList (&DhcpSb->Children, &Instance->Link);
    608   DhcpSb->NumChildren++;
    609 
    610   gBS->RestoreTPL (OldTpl);
    611 
    612   return EFI_SUCCESS;
    613 }
    614 
    615 
    616 /**
    617   Destroys a child handle with a protocol installed on it.
    618 
    619   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
    620   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
    621   last protocol on ChildHandle, then ChildHandle is destroyed.
    622 
    623   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    624   @param  ChildHandle Handle of the child to destroy
    625 
    626   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
    627   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
    628   @retval EFI_INVALID_PARAMETER Child handle is NULL.
    629   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
    630                                 because its services are being used.
    631   @retval other                 The child handle was not destroyed
    632 
    633 **/
    634 EFI_STATUS
    635 EFIAPI
    636 Dhcp4ServiceBindingDestroyChild (
    637   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
    638   IN EFI_HANDLE                    ChildHandle
    639   )
    640 {
    641   DHCP_SERVICE              *DhcpSb;
    642   DHCP_PROTOCOL             *Instance;
    643   EFI_DHCP4_PROTOCOL        *Dhcp;
    644   EFI_TPL                   OldTpl;
    645   EFI_STATUS                Status;
    646 
    647   if ((This == NULL) || (ChildHandle == NULL)) {
    648     return EFI_INVALID_PARAMETER;
    649   }
    650 
    651   //
    652   // Retrieve the private context data structures
    653   //
    654   Status = gBS->OpenProtocol (
    655                   ChildHandle,
    656                   &gEfiDhcp4ProtocolGuid,
    657                   (VOID **) &Dhcp,
    658                   gDhcp4DriverBinding.DriverBindingHandle,
    659                   ChildHandle,
    660                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    661                   );
    662 
    663   if (EFI_ERROR (Status)) {
    664     return EFI_UNSUPPORTED;
    665   }
    666 
    667   Instance  = DHCP_INSTANCE_FROM_THIS (Dhcp);
    668   DhcpSb    = DHCP_SERVICE_FROM_THIS (This);
    669 
    670   if (Instance->Service != DhcpSb) {
    671     return EFI_INVALID_PARAMETER;
    672   }
    673 
    674   //
    675   // A child can be destroyed more than once. For example,
    676   // Dhcp4DriverBindingStop will destroy all of its children.
    677   // when caller driver is being stopped, it will destroy the
    678   // dhcp child it opens.
    679   //
    680   if (Instance->InDestroy) {
    681     return EFI_SUCCESS;
    682   }
    683 
    684   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    685   Instance->InDestroy = TRUE;
    686 
    687   //
    688   // Close the Udp4 protocol.
    689   //
    690   gBS->CloseProtocol (
    691          DhcpSb->UdpIo->UdpHandle,
    692          &gEfiUdp4ProtocolGuid,
    693          gDhcp4DriverBinding.DriverBindingHandle,
    694          ChildHandle
    695          );
    696 
    697   //
    698   // Uninstall the DHCP4 protocol first to enable a top down destruction.
    699   //
    700   gBS->RestoreTPL (OldTpl);
    701   Status = gBS->UninstallProtocolInterface (
    702                   ChildHandle,
    703                   &gEfiDhcp4ProtocolGuid,
    704                   Dhcp
    705                   );
    706   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    707   if (EFI_ERROR (Status)) {
    708     Instance->InDestroy = FALSE;
    709 
    710     gBS->RestoreTPL (OldTpl);
    711     return Status;
    712   }
    713 
    714   if (DhcpSb->ActiveChild == Instance) {
    715     DhcpYieldControl (DhcpSb);
    716   }
    717 
    718   RemoveEntryList (&Instance->Link);
    719   DhcpSb->NumChildren--;
    720 
    721   if (Instance->UdpIo != NULL) {
    722     UdpIoCleanIo (Instance->UdpIo);
    723     gBS->CloseProtocol (
    724            Instance->UdpIo->UdpHandle,
    725            &gEfiUdp4ProtocolGuid,
    726            Instance->Service->Image,
    727            Instance->Handle
    728            );
    729     UdpIoFreeIo (Instance->UdpIo);
    730     Instance->UdpIo = NULL;
    731     Instance->Token = NULL;
    732   }
    733 
    734   gBS->RestoreTPL (OldTpl);
    735 
    736   FreePool (Instance);
    737   return EFI_SUCCESS;
    738 }
    739