Home | History | Annotate | Download | only in Dhcp6Dxe
      1 /** @file
      2   Driver Binding functions and Service Binding functions
      3   implementationfor for Dhcp6 Driver.
      4 
      5   Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Dhcp6Impl.h"
     18 
     19 
     20 EFI_DRIVER_BINDING_PROTOCOL gDhcp6DriverBinding = {
     21   Dhcp6DriverBindingSupported,
     22   Dhcp6DriverBindingStart,
     23   Dhcp6DriverBindingStop,
     24   0xa,
     25   NULL,
     26   NULL
     27 };
     28 
     29 EFI_SERVICE_BINDING_PROTOCOL gDhcp6ServiceBindingTemplate = {
     30   Dhcp6ServiceBindingCreateChild,
     31   Dhcp6ServiceBindingDestroyChild
     32 };
     33 
     34 /**
     35   Configure the default Udp6Io to receive all the DHCP6 traffic
     36   on this network interface.
     37 
     38   @param[in]  UdpIo                  The pointer to Udp6Io to be configured.
     39   @param[in]  Context                The pointer to the context.
     40 
     41   @retval EFI_SUCCESS            The Udp6Io is successfully configured.
     42   @retval Others                 Failed to configure the Udp6Io.
     43 
     44 **/
     45 EFI_STATUS
     46 EFIAPI
     47 Dhcp6ConfigureUdpIo (
     48   IN UDP_IO                 *UdpIo,
     49   IN VOID                   *Context
     50   )
     51 {
     52   EFI_UDP6_PROTOCOL         *Udp6;
     53   EFI_UDP6_CONFIG_DATA      *Config;
     54 
     55   Udp6   = UdpIo->Protocol.Udp6;
     56   Config = &(UdpIo->Config.Udp6);
     57 
     58   ZeroMem (Config, sizeof (EFI_UDP6_CONFIG_DATA));
     59 
     60   //
     61   // Set Udp6 configure data for the Dhcp6 instance.
     62   //
     63   Config->AcceptPromiscuous  = FALSE;
     64   Config->AcceptAnyPort      = FALSE;
     65   Config->AllowDuplicatePort = FALSE;
     66   Config->TrafficClass       = 0;
     67   Config->HopLimit           = 128;
     68   Config->ReceiveTimeout     = 0;
     69   Config->TransmitTimeout    = 0;
     70 
     71   //
     72   // Configure an endpoint of client(0, 546), server(0, 0), the addresses
     73   // will be overridden later. Note that we MUST not limit RemotePort.
     74   // More details, refer to RFC 3315 section 5.2.
     75   //
     76   Config->StationPort        = DHCP6_PORT_CLIENT;
     77   Config->RemotePort         = 0;
     78 
     79   return Udp6->Configure (Udp6, Config);;
     80 }
     81 
     82 
     83 /**
     84   Destroy the Dhcp6 service. The Dhcp6 service may be partly initialized,
     85   or partly destroyed. If a resource is destroyed, it is marked as such in
     86   case the destroy failed and being called again later.
     87 
     88   @param[in, out]  Service       The pointer to Dhcp6 service to be destroyed.
     89 
     90 **/
     91 VOID
     92 Dhcp6DestroyService (
     93   IN OUT DHCP6_SERVICE          *Service
     94   )
     95 {
     96   //
     97   // All children instances should have been already destroyed here.
     98   //
     99   ASSERT (Service->NumOfChild == 0);
    100 
    101   if (Service->ClientId != NULL) {
    102     FreePool (Service->ClientId);
    103   }
    104 
    105   if (Service->UdpIo != NULL) {
    106     UdpIoFreeIo (Service->UdpIo);
    107   }
    108 
    109   FreePool (Service);
    110 }
    111 
    112 
    113 /**
    114   Create a new Dhcp6 service for the Nic controller.
    115 
    116   @param[in]  Controller             The controller to be installed DHCP6 service
    117                                      binding protocol.
    118   @param[in]  ImageHandle            The image handle of the Dhcp6 driver.
    119   @param[out] Service                The return pointer of the new Dhcp6 service.
    120 
    121   @retval EFI_SUCCESS            The Dhcp6 service is created successfully.
    122   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    123   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource.
    124 
    125 **/
    126 EFI_STATUS
    127 Dhcp6CreateService (
    128   IN  EFI_HANDLE            Controller,
    129   IN  EFI_HANDLE            ImageHandle,
    130   OUT DHCP6_SERVICE         **Service
    131   )
    132 {
    133   DHCP6_SERVICE             *Dhcp6Srv;
    134   EFI_STATUS                Status;
    135 
    136   *Service = NULL;
    137   Dhcp6Srv = AllocateZeroPool (sizeof (DHCP6_SERVICE));
    138 
    139   if (Dhcp6Srv == NULL) {
    140     return EFI_OUT_OF_RESOURCES;
    141   }
    142 
    143   //
    144   // Open the SNP protocol to get mode data later.
    145   //
    146   Dhcp6Srv->Snp = NULL;
    147   NetLibGetSnpHandle (Controller, &Dhcp6Srv->Snp);
    148   if (Dhcp6Srv->Snp == NULL) {
    149     FreePool (Dhcp6Srv);
    150     return EFI_DEVICE_ERROR;
    151   }
    152 
    153   //
    154   // Initialize the fields of the new Dhcp6 service.
    155   //
    156   Dhcp6Srv->Signature       = DHCP6_SERVICE_SIGNATURE;
    157   Dhcp6Srv->Controller      = Controller;
    158   Dhcp6Srv->Image           = ImageHandle;
    159   Dhcp6Srv->Xid             = (0xffffff & NET_RANDOM (NetRandomInitSeed ()));
    160 
    161   CopyMem (
    162     &Dhcp6Srv->ServiceBinding,
    163     &gDhcp6ServiceBindingTemplate,
    164     sizeof (EFI_SERVICE_BINDING_PROTOCOL)
    165     );
    166 
    167   //
    168   // Locate Ip6->Ip6Config and store it for get IP6 Duplicate Address Detection transmits.
    169   //
    170   Status = gBS->HandleProtocol (
    171                   Controller,
    172                   &gEfiIp6ConfigProtocolGuid,
    173                   (VOID **) &Dhcp6Srv->Ip6Cfg
    174                   );
    175   if (EFI_ERROR (Status)) {
    176     FreePool (Dhcp6Srv);
    177     return Status;
    178   }
    179 
    180   //
    181   // Generate client Duid: If SMBIOS system UUID is located, generate DUID in DUID-UUID format.
    182   // Otherwise, in DUID-LLT format.
    183   //
    184   Dhcp6Srv->ClientId        = Dhcp6GenerateClientId (Dhcp6Srv->Snp->Mode);
    185 
    186   if (Dhcp6Srv->ClientId == NULL) {
    187     FreePool (Dhcp6Srv);
    188     return EFI_DEVICE_ERROR;
    189   }
    190 
    191   //
    192   // Create an Udp6Io for stateful transmit/receive of each Dhcp6 instance.
    193   //
    194   Dhcp6Srv->UdpIo = UdpIoCreateIo (
    195                       Controller,
    196                       ImageHandle,
    197                       Dhcp6ConfigureUdpIo,
    198                       UDP_IO_UDP6_VERSION,
    199                       NULL
    200                       );
    201 
    202   if (Dhcp6Srv->UdpIo == NULL) {
    203     FreePool (Dhcp6Srv->ClientId);
    204     FreePool (Dhcp6Srv);
    205     return EFI_DEVICE_ERROR;
    206   }
    207 
    208   InitializeListHead (&Dhcp6Srv->Child);
    209 
    210   *Service = Dhcp6Srv;
    211 
    212   return EFI_SUCCESS;
    213 }
    214 
    215 
    216 /**
    217   Destroy the Dhcp6 instance and recycle the resources.
    218 
    219   @param[in, out]  Instance        The pointer to the Dhcp6 instance.
    220 
    221 **/
    222 VOID
    223 Dhcp6DestroyInstance (
    224   IN OUT DHCP6_INSTANCE         *Instance
    225   )
    226 {
    227   //
    228   // Clean up the retry list first.
    229   //
    230   Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);
    231   gBS->CloseEvent (Instance->Timer);
    232 
    233   //
    234   // Clean up the current configure data.
    235   //
    236   if (Instance->Config != NULL) {
    237     Dhcp6CleanupConfigData (Instance->Config);
    238     FreePool (Instance->Config);
    239   }
    240 
    241   //
    242   // Clean up the current Ia.
    243   //
    244   if (Instance->IaCb.Ia != NULL) {
    245     if (Instance->IaCb.Ia->ReplyPacket != NULL) {
    246       FreePool (Instance->IaCb.Ia->ReplyPacket);
    247     }
    248     FreePool (Instance->IaCb.Ia);
    249   }
    250 
    251   if (Instance->Unicast != NULL) {
    252     FreePool (Instance->Unicast);
    253   }
    254 
    255   if (Instance->AdSelect != NULL) {
    256     FreePool (Instance->AdSelect);
    257   }
    258 
    259   FreePool (Instance);
    260 }
    261 
    262 
    263 /**
    264   Create the Dhcp6 instance and initialize it.
    265 
    266   @param[in]  Service              The pointer to the Dhcp6 service.
    267   @param[out] Instance             The pointer to the Dhcp6 instance.
    268 
    269   @retval EFI_SUCCESS            The Dhcp6 instance is created.
    270   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
    271 
    272 **/
    273 EFI_STATUS
    274 Dhcp6CreateInstance (
    275   IN  DHCP6_SERVICE         *Service,
    276   OUT DHCP6_INSTANCE        **Instance
    277   )
    278 {
    279   EFI_STATUS                Status;
    280   DHCP6_INSTANCE            *Dhcp6Ins;
    281 
    282   *Instance = NULL;
    283   Dhcp6Ins  = AllocateZeroPool (sizeof (DHCP6_INSTANCE));
    284 
    285   if (Dhcp6Ins == NULL) {
    286     return EFI_OUT_OF_RESOURCES;
    287   }
    288 
    289   //
    290   // Initialize the fields of the new Dhcp6 instance.
    291   //
    292   Dhcp6Ins->Signature       = DHCP6_INSTANCE_SIGNATURE;
    293   Dhcp6Ins->UdpSts          = EFI_ALREADY_STARTED;
    294   Dhcp6Ins->Service         = Service;
    295   Dhcp6Ins->InDestroy       = FALSE;
    296   Dhcp6Ins->MediaPresent    = TRUE;
    297 
    298   CopyMem (
    299     &Dhcp6Ins->Dhcp6,
    300     &gDhcp6ProtocolTemplate,
    301     sizeof (EFI_DHCP6_PROTOCOL)
    302     );
    303 
    304   InitializeListHead (&Dhcp6Ins->TxList);
    305   InitializeListHead (&Dhcp6Ins->InfList);
    306 
    307   //
    308   // There is a timer for each Dhcp6 instance, which is used to track the
    309   // lease time of Ia and the retransmisson time of all sent packets.
    310   //
    311   Status = gBS->CreateEvent (
    312                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    313                   TPL_CALLBACK,
    314                   Dhcp6OnTimerTick,
    315                   Dhcp6Ins,
    316                   &Dhcp6Ins->Timer
    317                   );
    318 
    319   if (EFI_ERROR (Status)) {
    320     FreePool (Dhcp6Ins);
    321     return Status;
    322   }
    323 
    324   *Instance = Dhcp6Ins;
    325 
    326   return EFI_SUCCESS;
    327 }
    328 
    329 /**
    330   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    331 
    332   @param[in]    Entry           The entry to be removed.
    333   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    334 
    335   @retval EFI_SUCCESS           The entry has been removed successfully.
    336   @retval Others                Fail to remove the entry.
    337 
    338 **/
    339 EFI_STATUS
    340 EFIAPI
    341 Dhcp6DestroyChildEntry (
    342   IN LIST_ENTRY         *Entry,
    343   IN VOID               *Context
    344   )
    345 {
    346   DHCP6_INSTANCE                   *Instance;
    347   EFI_SERVICE_BINDING_PROTOCOL     *ServiceBinding;
    348 
    349   if (Entry == NULL || Context == NULL) {
    350     return EFI_INVALID_PARAMETER;
    351   }
    352 
    353   Instance = NET_LIST_USER_STRUCT_S (Entry, DHCP6_INSTANCE, Link, DHCP6_INSTANCE_SIGNATURE);
    354   ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;
    355 
    356   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
    357 }
    358 
    359 
    360 /**
    361   Entry point of the DHCP6 driver to install various protocols.
    362 
    363   @param[in]  ImageHandle           The handle of the UEFI image file.
    364   @param[in]  SystemTable           The pointer to the EFI System Table.
    365 
    366   @retval EFI_SUCCESS           The operation completed successfully.
    367   @retval Others                Unexpected error occurs.
    368 
    369 **/
    370 EFI_STATUS
    371 EFIAPI
    372 Dhcp6DriverEntryPoint (
    373   IN EFI_HANDLE                   ImageHandle,
    374   IN EFI_SYSTEM_TABLE             *SystemTable
    375   )
    376 {
    377   return EfiLibInstallDriverBindingComponentName2 (
    378            ImageHandle,
    379            SystemTable,
    380            &gDhcp6DriverBinding,
    381            ImageHandle,
    382            &gDhcp6ComponentName,
    383            &gDhcp6ComponentName2
    384            );
    385 }
    386 
    387 
    388 /**
    389   Test to see if this driver supports ControllerHandle. This service
    390   is called by the EFI boot service ConnectController(). In
    391   order to make drivers as small as possible, there are a few calling
    392   restrictions for this service. ConnectController() must
    393   follow these calling restrictions. If any other agent wishes to call
    394   Supported() it must also follow these calling restrictions.
    395 
    396   @param[in]  This                The pointer to the driver binding protocol.
    397   @param[in]  ControllerHandle    The handle of device to be tested.
    398   @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
    399                                   device to be started.
    400 
    401   @retval EFI_SUCCESS         This driver supports this device.
    402   @retval Others              This driver does not support this device.
    403 
    404 **/
    405 EFI_STATUS
    406 EFIAPI
    407 Dhcp6DriverBindingSupported (
    408   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    409   IN EFI_HANDLE                   ControllerHandle,
    410   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    411   )
    412 {
    413   return gBS->OpenProtocol (
    414                 ControllerHandle,
    415                 &gEfiUdp6ServiceBindingProtocolGuid,
    416                 NULL,
    417                 This->DriverBindingHandle,
    418                 ControllerHandle,
    419                 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    420                 );
    421 }
    422 
    423 
    424 /**
    425   Start this driver on ControllerHandle. This service is called by the
    426   EFI boot service ConnectController(). In order to make
    427   drivers as small as possible, there are a few calling restrictions for
    428   this service. ConnectController() must follow these
    429   calling restrictions. If any other agent wishes to call Start() it
    430   must also follow these calling restrictions.
    431 
    432   @param[in]  This                 The pointer to the driver binding protocol.
    433   @param[in]  ControllerHandle     The handle of device to be started.
    434   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
    435                                    device to be started.
    436 
    437   @retval EFI_SUCCESS          This driver is installed to ControllerHandle.
    438   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.
    439   @retval other                This driver does not support this device.
    440 
    441 **/
    442 EFI_STATUS
    443 EFIAPI
    444 Dhcp6DriverBindingStart (
    445   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    446   IN EFI_HANDLE                   ControllerHandle,
    447   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    448   )
    449 {
    450   EFI_STATUS                      Status;
    451   DHCP6_SERVICE                   *Service;
    452 
    453   //
    454   // Check the Dhcp6 serivce whether already started.
    455   //
    456   Status = gBS->OpenProtocol (
    457                   ControllerHandle,
    458                   &gEfiDhcp6ServiceBindingProtocolGuid,
    459                   NULL,
    460                   This->DriverBindingHandle,
    461                   ControllerHandle,
    462                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    463                   );
    464 
    465   if (!EFI_ERROR (Status)) {
    466     return EFI_ALREADY_STARTED;
    467   }
    468 
    469   //
    470   // Create and initialize the Dhcp6 service.
    471   //
    472   Status = Dhcp6CreateService (
    473              ControllerHandle,
    474              This->DriverBindingHandle,
    475              &Service
    476              );
    477 
    478   if (EFI_ERROR (Status)) {
    479     return Status;
    480   }
    481 
    482   ASSERT (Service != NULL);
    483 
    484   Status = gBS->InstallMultipleProtocolInterfaces (
    485                   &ControllerHandle,
    486                   &gEfiDhcp6ServiceBindingProtocolGuid,
    487                   &Service->ServiceBinding,
    488                   NULL
    489                   );
    490 
    491   if (EFI_ERROR (Status)) {
    492     Dhcp6DestroyService (Service);
    493     return Status;
    494   }
    495 
    496   return EFI_SUCCESS;
    497 }
    498 
    499 
    500 /**
    501   Stop this driver on ControllerHandle. This service is called by the
    502   EFI boot service DisconnectController(). In order to
    503   make drivers as small as possible, there are a few calling
    504   restrictions for this service. DisconnectController()
    505   must follow these calling restrictions. If any other agent wishes
    506   to call Stop() it must also follow these calling restrictions.
    507 
    508   @param[in]  This              Protocol instance pointer.
    509   @param[in]  ControllerHandle  Handle of device to stop driver on
    510   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    511                                 children is zero stop the entire bus driver.
    512   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
    513 
    514   @retval EFI_SUCCESS           This driver is removed ControllerHandle
    515   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    516   @retval other                 This driver was not removed from this device
    517 
    518 **/
    519 EFI_STATUS
    520 EFIAPI
    521 Dhcp6DriverBindingStop (
    522   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    523   IN  EFI_HANDLE                   ControllerHandle,
    524   IN  UINTN                        NumberOfChildren,
    525   IN  EFI_HANDLE                   *ChildHandleBuffer   OPTIONAL
    526   )
    527 {
    528   EFI_STATUS                       Status;
    529   EFI_HANDLE                       NicHandle;
    530   EFI_SERVICE_BINDING_PROTOCOL     *ServiceBinding;
    531   DHCP6_SERVICE                    *Service;
    532   LIST_ENTRY                       *List;
    533   UINTN                            ListLength;
    534 
    535   //
    536   // Find and check the Nic handle by the controller handle.
    537   //
    538   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);
    539 
    540   if (NicHandle == NULL) {
    541     return EFI_SUCCESS;
    542   }
    543 
    544   Status = gBS->OpenProtocol (
    545                   NicHandle,
    546                   &gEfiDhcp6ServiceBindingProtocolGuid,
    547                   (VOID **) &ServiceBinding,
    548                   This->DriverBindingHandle,
    549                   NicHandle,
    550                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    551                   );
    552 
    553   if (EFI_ERROR (Status)) {
    554     return Status;
    555   }
    556 
    557   Service = DHCP6_SERVICE_FROM_THIS (ServiceBinding);
    558   if (!IsListEmpty (&Service->Child)) {
    559     //
    560     // Destroy all the children instances before destory the service.
    561     //
    562     List = &Service->Child;
    563     Status = NetDestroyLinkList (
    564                List,
    565                Dhcp6DestroyChildEntry,
    566                ServiceBinding,
    567                &ListLength
    568                );
    569     if (EFI_ERROR (Status) || ListLength != 0) {
    570       Status = EFI_DEVICE_ERROR;
    571     }
    572   }
    573 
    574   if (NumberOfChildren == 0 && !IsListEmpty (&Service->Child)) {
    575     Status = EFI_DEVICE_ERROR;
    576   }
    577 
    578   if (NumberOfChildren == 0 && IsListEmpty (&Service->Child)) {
    579     //
    580     // Destroy the service itself if no child instance left.
    581     //
    582     Status = gBS->UninstallProtocolInterface (
    583                     NicHandle,
    584                     &gEfiDhcp6ServiceBindingProtocolGuid,
    585                     ServiceBinding
    586                     );
    587     if (EFI_ERROR (Status)) {
    588       goto ON_EXIT;
    589     }
    590 
    591     Dhcp6DestroyService (Service);
    592     Status = EFI_SUCCESS;
    593   }
    594 
    595 ON_EXIT:
    596   return Status;
    597 }
    598 
    599 
    600 /**
    601   Creates a child handle and installs a protocol.
    602 
    603   The CreateChild() function installs a protocol on ChildHandle.
    604   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
    605   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
    606 
    607   @param[in]      This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    608   @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL,
    609                               then a new handle is created. If it is a pointer to an existing
    610                               UEFI handle, then the protocol is added to the existing UEFI handle.
    611 
    612   @retval EFI_SUCCES            The protocol was added to ChildHandle.
    613   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
    614   @retval other                 The child handle was not created.
    615 
    616 **/
    617 EFI_STATUS
    618 EFIAPI
    619 Dhcp6ServiceBindingCreateChild (
    620   IN     EFI_SERVICE_BINDING_PROTOCOL  *This,
    621   IN OUT EFI_HANDLE                    *ChildHandle
    622   )
    623 {
    624   EFI_STATUS                       Status;
    625   EFI_TPL                          OldTpl;
    626   DHCP6_SERVICE                    *Service;
    627   DHCP6_INSTANCE                   *Instance;
    628   VOID                             *Udp6;
    629 
    630   if (This == NULL || ChildHandle == NULL) {
    631     return EFI_INVALID_PARAMETER;
    632   }
    633 
    634   Service = DHCP6_SERVICE_FROM_THIS (This);
    635 
    636   Status  = Dhcp6CreateInstance (Service, &Instance);
    637 
    638   if (EFI_ERROR (Status)) {
    639     return Status;
    640   }
    641 
    642   ASSERT (Instance != NULL);
    643 
    644   //
    645   // Start the timer when the instance is ready to use.
    646   //
    647   Status = gBS->SetTimer (
    648                   Instance->Timer,
    649                   TimerPeriodic,
    650                   TICKS_PER_SECOND
    651                   );
    652 
    653   if (EFI_ERROR (Status)) {
    654     goto ON_ERROR;
    655   }
    656 
    657   //
    658   // Install the DHCP6 protocol onto ChildHandle.
    659   //
    660   Status = gBS->InstallMultipleProtocolInterfaces (
    661                   ChildHandle,
    662                   &gEfiDhcp6ProtocolGuid,
    663                   &Instance->Dhcp6,
    664                   NULL
    665                   );
    666 
    667   if (EFI_ERROR (Status)) {
    668     goto ON_ERROR;
    669   }
    670 
    671   Instance->Handle = *ChildHandle;
    672 
    673   //
    674   // Open the UDP6 protocol BY_CHILD.
    675   //
    676   Status = gBS->OpenProtocol (
    677                   Service->UdpIo->UdpHandle,
    678                   &gEfiUdp6ProtocolGuid,
    679                   (VOID **) &Udp6,
    680                   gDhcp6DriverBinding.DriverBindingHandle,
    681                   Instance->Handle,
    682                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    683                   );
    684 
    685   if (EFI_ERROR (Status)) {
    686 
    687     gBS->UninstallMultipleProtocolInterfaces (
    688            Instance->Handle,
    689            &gEfiDhcp6ProtocolGuid,
    690            &Instance->Dhcp6,
    691            NULL
    692            );
    693     goto ON_ERROR;
    694   }
    695 
    696   //
    697   // Add into the children list of its parent service.
    698   //
    699   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    700 
    701   InsertTailList (&Service->Child, &Instance->Link);
    702   Service->NumOfChild++;
    703 
    704   gBS->RestoreTPL (OldTpl);
    705   return EFI_SUCCESS;
    706 
    707 ON_ERROR:
    708 
    709   Dhcp6DestroyInstance (Instance);
    710   return Status;
    711 }
    712 
    713 
    714 /**
    715   Destroys a child handle with a protocol installed on it.
    716 
    717   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
    718   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
    719   last protocol on ChildHandle, then ChildHandle is destroyed.
    720 
    721   @param[in]  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    722   @param[in]  ChildHandle Handle of the child to destroy
    723 
    724   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
    725   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
    726   @retval EFI_INVALID_PARAMETER Child handle is NULL.
    727   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
    728                                 because its services are being used.
    729   @retval other                 The child handle was not destroyed
    730 
    731 **/
    732 EFI_STATUS
    733 EFIAPI
    734 Dhcp6ServiceBindingDestroyChild (
    735   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
    736   IN EFI_HANDLE                    ChildHandle
    737   )
    738 {
    739   EFI_STATUS                       Status;
    740   EFI_TPL                          OldTpl;
    741   EFI_DHCP6_PROTOCOL               *Dhcp6;
    742   DHCP6_SERVICE                    *Service;
    743   DHCP6_INSTANCE                   *Instance;
    744 
    745   if (This == NULL || ChildHandle == NULL) {
    746     return EFI_INVALID_PARAMETER;
    747   }
    748 
    749   //
    750   // Retrieve the private context data structures
    751   //
    752   Status = gBS->OpenProtocol (
    753                   ChildHandle,
    754                   &gEfiDhcp6ProtocolGuid,
    755                   (VOID **) &Dhcp6,
    756                   gDhcp6DriverBinding.DriverBindingHandle,
    757                   ChildHandle,
    758                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    759                   );
    760 
    761   if (EFI_ERROR (Status)) {
    762     return EFI_UNSUPPORTED;
    763   }
    764 
    765   Instance = DHCP6_INSTANCE_FROM_THIS (Dhcp6);
    766   Service  = DHCP6_SERVICE_FROM_THIS (This);
    767 
    768   if (Instance->Service != Service) {
    769     return EFI_INVALID_PARAMETER;
    770   }
    771 
    772   if (Instance->InDestroy) {
    773     return EFI_SUCCESS;
    774   }
    775 
    776   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    777 
    778   Instance->InDestroy = TRUE;
    779 
    780   Status = gBS->CloseProtocol (
    781                   Service->UdpIo->UdpHandle,
    782                   &gEfiUdp6ProtocolGuid,
    783                   gDhcp6DriverBinding.DriverBindingHandle,
    784                   ChildHandle
    785                   );
    786 
    787   if (EFI_ERROR (Status)) {
    788     Instance->InDestroy = FALSE;
    789     gBS->RestoreTPL (OldTpl);
    790     return Status;
    791   }
    792 
    793   //
    794   // Uninstall the MTFTP6 protocol first to enable a top down destruction.
    795   //
    796   gBS->RestoreTPL (OldTpl);
    797   Status = gBS->UninstallProtocolInterface (
    798                   ChildHandle,
    799                   &gEfiDhcp6ProtocolGuid,
    800                   Dhcp6
    801                   );
    802   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    803   if (EFI_ERROR (Status)) {
    804     Instance->InDestroy = FALSE;
    805     gBS->RestoreTPL (OldTpl);
    806     return Status;
    807   }
    808 
    809   //
    810   // Remove it from the children list of its parent service.
    811   //
    812   RemoveEntryList (&Instance->Link);
    813   Service->NumOfChild--;
    814 
    815   gBS->RestoreTPL (OldTpl);
    816 
    817   Dhcp6DestroyInstance (Instance);
    818   return EFI_SUCCESS;
    819 }
    820