Home | History | Annotate | Download | only in Mtftp4Dxe
      1 /** @file
      2   Implementation of Mtftp drivers.
      3 
      4 Copyright (c) 2006 - 2012, 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<BR>
      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 "Mtftp4Impl.h"
     16 
     17 EFI_DRIVER_BINDING_PROTOCOL   gMtftp4DriverBinding = {
     18   Mtftp4DriverBindingSupported,
     19   Mtftp4DriverBindingStart,
     20   Mtftp4DriverBindingStop,
     21   0xa,
     22   NULL,
     23   NULL
     24 };
     25 
     26 EFI_SERVICE_BINDING_PROTOCOL  gMtftp4ServiceBindingTemplete = {
     27   Mtftp4ServiceBindingCreateChild,
     28   Mtftp4ServiceBindingDestroyChild
     29 };
     30 
     31 
     32 /**
     33   The driver entry point which installs multiple protocols to the ImageHandle.
     34 
     35   @param ImageHandle    The MTFTP's image handle.
     36   @param SystemTable    The system table.
     37 
     38   @retval EFI_SUCCESS  The handles are successfully installed on the image.
     39   @retval others       some EFI_ERROR occured.
     40 
     41 **/
     42 EFI_STATUS
     43 EFIAPI
     44 Mtftp4DriverEntryPoint (
     45   IN EFI_HANDLE             ImageHandle,
     46   IN EFI_SYSTEM_TABLE       *SystemTable
     47   )
     48 {
     49   return EfiLibInstallDriverBindingComponentName2 (
     50            ImageHandle,
     51            SystemTable,
     52            &gMtftp4DriverBinding,
     53            ImageHandle,
     54            &gMtftp4ComponentName,
     55            &gMtftp4ComponentName2
     56            );
     57 }
     58 
     59 
     60 /**
     61   Test whether MTFTP driver support this controller.
     62 
     63   @param  This                   The MTFTP driver binding instance
     64   @param  Controller             The controller to test
     65   @param  RemainingDevicePath    The remaining device path
     66 
     67   @retval EFI_SUCCESS            The controller has UDP service binding protocol
     68                                  installed, MTFTP can support it.
     69   @retval EFI_ALREADY_STARTED    The device specified by ControllerHandle and
     70                                  RemainingDevicePath is already being managed by
     71                                  the driver specified by This.
     72   @retval EFI_ACCESS_DENIED      The device specified by ControllerHandle and
     73                                  RemainingDevicePath is already being managed by a
     74                                  different driver or an application that requires
     75                                  exclusive access.
     76   @retval EFI_UNSUPPORTED        The device specified by ControllerHandle and
     77                                  RemainingDevicePath is not supported by the driver
     78                                  specified by This.
     79 
     80 **/
     81 EFI_STATUS
     82 EFIAPI
     83 Mtftp4DriverBindingSupported (
     84   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     85   IN EFI_HANDLE                     Controller,
     86   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
     87   )
     88 {
     89   EFI_STATUS  Status;
     90 
     91   Status = gBS->OpenProtocol (
     92                   Controller,
     93                   &gEfiUdp4ServiceBindingProtocolGuid,
     94                   NULL,
     95                   This->DriverBindingHandle,
     96                   Controller,
     97                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
     98                   );
     99 
    100   return Status;
    101 }
    102 
    103 
    104 /**
    105   Config a NULL UDP that is used to keep the connection between UDP and MTFTP.
    106 
    107   Just leave the Udp child unconfigured. When UDP is unloaded,
    108     MTFTP will be informed with DriverBinding Stop.
    109 
    110   @param  UdpIo                  The UDP_IO to configure
    111   @param  Context                The opaque parameter to the callback
    112 
    113   @retval EFI_SUCCESS            It always return EFI_SUCCESS directly.
    114 
    115 **/
    116 EFI_STATUS
    117 EFIAPI
    118 Mtftp4ConfigNullUdp (
    119   IN UDP_IO                 *UdpIo,
    120   IN VOID                   *Context
    121   )
    122 {
    123   return EFI_SUCCESS;
    124 }
    125 
    126 
    127 /**
    128   Create then initialize a MTFTP service binding instance.
    129 
    130   @param  Controller             The controller to install the MTFTP service
    131                                  binding on
    132   @param  Image                  The driver binding image of the MTFTP driver
    133   @param  Service                The variable to receive the created service
    134                                  binding instance.
    135 
    136   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource to create the instance
    137   @retval EFI_DEVICE_ERROR       Failed to create a NULL UDP port to keep
    138                                  connection  with UDP.
    139   @retval EFI_SUCCESS            The service instance is created for the
    140                                  controller.
    141 
    142 **/
    143 EFI_STATUS
    144 Mtftp4CreateService (
    145   IN     EFI_HANDLE            Controller,
    146   IN     EFI_HANDLE            Image,
    147      OUT MTFTP4_SERVICE        **Service
    148   )
    149 {
    150   MTFTP4_SERVICE            *MtftpSb;
    151   EFI_STATUS                Status;
    152 
    153   *Service  = NULL;
    154   MtftpSb   = AllocatePool (sizeof (MTFTP4_SERVICE));
    155 
    156   if (MtftpSb == NULL) {
    157     return EFI_OUT_OF_RESOURCES;
    158   }
    159 
    160   MtftpSb->Signature      = MTFTP4_SERVICE_SIGNATURE;
    161   MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
    162   MtftpSb->ChildrenNum    = 0;
    163   InitializeListHead (&MtftpSb->Children);
    164 
    165   MtftpSb->Timer          = NULL;
    166   MtftpSb->TimerToGetMap  = NULL;
    167   MtftpSb->Controller     = Controller;
    168   MtftpSb->Image          = Image;
    169   MtftpSb->ConnectUdp     = NULL;
    170 
    171   //
    172   // Create the timer and a udp to be notified when UDP is uninstalled
    173   //
    174   Status = gBS->CreateEvent (
    175                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    176                   TPL_CALLBACK,
    177                   Mtftp4OnTimerTick,
    178                   MtftpSb,
    179                   &MtftpSb->Timer
    180                   );
    181 
    182   if (EFI_ERROR (Status)) {
    183     FreePool (MtftpSb);
    184     return Status;
    185   }
    186 
    187   //
    188   // Create the timer used to time out the procedure which is used to
    189   // get the default IP address.
    190   //
    191   Status = gBS->CreateEvent (
    192                   EVT_TIMER,
    193                   TPL_CALLBACK,
    194                   NULL,
    195                   NULL,
    196                   &MtftpSb->TimerToGetMap
    197                   );
    198   if (EFI_ERROR (Status)) {
    199     gBS->CloseEvent (MtftpSb->Timer);
    200     FreePool (MtftpSb);
    201     return Status;
    202   }
    203 
    204   MtftpSb->ConnectUdp = UdpIoCreateIo (
    205                           Controller,
    206                           Image,
    207                           Mtftp4ConfigNullUdp,
    208                           UDP_IO_UDP4_VERSION,
    209                           NULL
    210                           );
    211 
    212   if (MtftpSb->ConnectUdp == NULL) {
    213     gBS->CloseEvent (MtftpSb->TimerToGetMap);
    214     gBS->CloseEvent (MtftpSb->Timer);
    215     FreePool (MtftpSb);
    216     return EFI_DEVICE_ERROR;
    217   }
    218 
    219   *Service = MtftpSb;
    220   return EFI_SUCCESS;
    221 }
    222 
    223 
    224 /**
    225   Release all the resource used the MTFTP service binding instance.
    226 
    227   @param  MtftpSb                The MTFTP service binding instance.
    228 
    229 **/
    230 VOID
    231 Mtftp4CleanService (
    232   IN MTFTP4_SERVICE     *MtftpSb
    233   )
    234 {
    235   UdpIoFreeIo (MtftpSb->ConnectUdp);
    236   gBS->CloseEvent (MtftpSb->TimerToGetMap);
    237   gBS->CloseEvent (MtftpSb->Timer);
    238 }
    239 
    240 
    241 /**
    242   Start the MTFTP driver on this controller.
    243 
    244   MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
    245   controller, which can be used to create/destroy MTFTP children.
    246 
    247   @param  This                   The MTFTP driver binding protocol.
    248   @param  Controller             The controller to manage.
    249   @param  RemainingDevicePath    Remaining device path.
    250 
    251   @retval EFI_ALREADY_STARTED    The MTFTP service binding protocol has been
    252                                  started  on the controller.
    253   @retval EFI_SUCCESS            The MTFTP service binding is installed on the
    254                                  controller.
    255 
    256 **/
    257 EFI_STATUS
    258 EFIAPI
    259 Mtftp4DriverBindingStart (
    260   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    261   IN EFI_HANDLE                   Controller,
    262   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    263   )
    264 {
    265   MTFTP4_SERVICE            *MtftpSb;
    266   EFI_STATUS                Status;
    267 
    268   //
    269   // Directly return if driver is already running.
    270   //
    271   Status = gBS->OpenProtocol (
    272                   Controller,
    273                   &gEfiMtftp4ServiceBindingProtocolGuid,
    274                   NULL,
    275                   This->DriverBindingHandle,
    276                   Controller,
    277                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    278                   );
    279 
    280   if (Status == EFI_SUCCESS) {
    281     return EFI_ALREADY_STARTED;
    282   }
    283 
    284   Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
    285 
    286   if (EFI_ERROR (Status)) {
    287     return Status;
    288   }
    289   ASSERT (MtftpSb != NULL);
    290 
    291   Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
    292 
    293   if (EFI_ERROR (Status)) {
    294     goto ON_ERROR;
    295   }
    296 
    297   //
    298   // Install the Mtftp4ServiceBinding Protocol onto Controller
    299   //
    300   Status = gBS->InstallMultipleProtocolInterfaces (
    301                   &Controller,
    302                   &gEfiMtftp4ServiceBindingProtocolGuid,
    303                   &MtftpSb->ServiceBinding,
    304                   NULL
    305                   );
    306 
    307   if (EFI_ERROR (Status)) {
    308     goto ON_ERROR;
    309   }
    310 
    311   return EFI_SUCCESS;
    312 
    313 ON_ERROR:
    314   Mtftp4CleanService (MtftpSb);
    315   FreePool (MtftpSb);
    316 
    317   return Status;
    318 }
    319 
    320 /**
    321   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    322 
    323   @param[in]    Entry           The entry to be removed.
    324   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    325 
    326   @retval EFI_SUCCESS           The entry has been removed successfully.
    327   @retval Others                Fail to remove the entry.
    328 
    329 **/
    330 EFI_STATUS
    331 EFIAPI
    332 Mtftp4DestroyChildEntryInHandleBuffer (
    333   IN LIST_ENTRY         *Entry,
    334   IN VOID               *Context
    335   )
    336 {
    337   MTFTP4_PROTOCOL               *Instance;
    338   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    339   UINTN                         NumberOfChildren;
    340   EFI_HANDLE                    *ChildHandleBuffer;
    341 
    342   if (Entry == NULL || Context == NULL) {
    343     return EFI_INVALID_PARAMETER;
    344   }
    345 
    346   Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP4_PROTOCOL, Link, MTFTP4_PROTOCOL_SIGNATURE);
    347   ServiceBinding    = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
    348   NumberOfChildren  = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
    349   ChildHandleBuffer = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
    350 
    351   if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
    352     return EFI_SUCCESS;
    353   }
    354 
    355   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
    356 }
    357 
    358 /**
    359   Stop the MTFTP driver on controller. The controller is a UDP
    360   child handle.
    361 
    362   @param  This                   The MTFTP driver binding protocol
    363   @param  Controller             The controller to stop
    364   @param  NumberOfChildren       The number of children
    365   @param  ChildHandleBuffer      The array of the child handle.
    366 
    367   @retval EFI_SUCCESS            The driver is stopped on the controller.
    368   @retval EFI_DEVICE_ERROR       Failed to stop the driver on the controller.
    369 
    370 **/
    371 EFI_STATUS
    372 EFIAPI
    373 Mtftp4DriverBindingStop (
    374   IN EFI_DRIVER_BINDING_PROTOCOL *This,
    375   IN EFI_HANDLE                  Controller,
    376   IN UINTN                       NumberOfChildren,
    377   IN EFI_HANDLE                  *ChildHandleBuffer
    378   )
    379 {
    380   EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
    381   MTFTP4_SERVICE                             *MtftpSb;
    382   EFI_HANDLE                                 NicHandle;
    383   EFI_STATUS                                 Status;
    384   LIST_ENTRY                                 *List;
    385   MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
    386 
    387   //
    388   // MTFTP driver opens UDP child, So, Controller is a UDP
    389   // child handle. Locate the Nic handle first. Then get the
    390   // MTFTP private data back.
    391   //
    392   NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
    393 
    394   if (NicHandle == NULL) {
    395     return EFI_SUCCESS;
    396   }
    397 
    398   Status = gBS->OpenProtocol (
    399                   NicHandle,
    400                   &gEfiMtftp4ServiceBindingProtocolGuid,
    401                   (VOID **) &ServiceBinding,
    402                   This->DriverBindingHandle,
    403                   NicHandle,
    404                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    405                   );
    406 
    407   if (EFI_ERROR (Status)) {
    408     return EFI_DEVICE_ERROR;
    409   }
    410 
    411   MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
    412 
    413   if (!IsListEmpty (&MtftpSb->Children)) {
    414     //
    415     // Destroy the Mtftp4 child instance in ChildHandleBuffer.
    416     //
    417     List = &MtftpSb->Children;
    418     Context.ServiceBinding    = ServiceBinding;
    419     Context.NumberOfChildren  = NumberOfChildren;
    420     Context.ChildHandleBuffer = ChildHandleBuffer;
    421     Status = NetDestroyLinkList (
    422                List,
    423                Mtftp4DestroyChildEntryInHandleBuffer,
    424                &Context,
    425                NULL
    426                );
    427   }
    428 
    429   if (NumberOfChildren == 0 && IsListEmpty (&MtftpSb->Children)) {
    430     gBS->UninstallProtocolInterface (
    431            NicHandle,
    432            &gEfiMtftp4ServiceBindingProtocolGuid,
    433            ServiceBinding
    434            );
    435 
    436     Mtftp4CleanService (MtftpSb);
    437     if (gMtftp4ControllerNameTable != NULL) {
    438       FreeUnicodeStringTable (gMtftp4ControllerNameTable);
    439       gMtftp4ControllerNameTable = NULL;
    440     }
    441     FreePool (MtftpSb);
    442 
    443     Status = EFI_SUCCESS;
    444   }
    445 
    446   return Status;
    447 }
    448 
    449 
    450 /**
    451   Initialize a MTFTP protocol instance which is the child of MtftpSb.
    452 
    453   @param  MtftpSb                The MTFTP service binding protocol.
    454   @param  Instance               The MTFTP instance to initialize.
    455 
    456 **/
    457 VOID
    458 Mtftp4InitProtocol (
    459   IN     MTFTP4_SERVICE         *MtftpSb,
    460      OUT MTFTP4_PROTOCOL        *Instance
    461   )
    462 {
    463   ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
    464 
    465   Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
    466   InitializeListHead (&Instance->Link);
    467   CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
    468   Instance->State     = MTFTP4_STATE_UNCONFIGED;
    469   Instance->Service   = MtftpSb;
    470 
    471   InitializeListHead (&Instance->Blocks);
    472 }
    473 
    474 
    475 /**
    476   Create a MTFTP child for the service binding instance, then
    477   install the MTFTP protocol to the ChildHandle.
    478 
    479   @param  This                   The MTFTP service binding instance.
    480   @param  ChildHandle            The Child handle to install the MTFTP protocol.
    481 
    482   @retval EFI_INVALID_PARAMETER  The parameter is invalid.
    483   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource for the new child.
    484   @retval EFI_SUCCESS            The child is successfully create.
    485 
    486 **/
    487 EFI_STATUS
    488 EFIAPI
    489 Mtftp4ServiceBindingCreateChild (
    490   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
    491   IN EFI_HANDLE                *ChildHandle
    492   )
    493 {
    494   MTFTP4_SERVICE            *MtftpSb;
    495   MTFTP4_PROTOCOL           *Instance;
    496   EFI_STATUS                Status;
    497   EFI_TPL                   OldTpl;
    498   VOID                      *Udp4;
    499 
    500   if ((This == NULL) || (ChildHandle == NULL)) {
    501     return EFI_INVALID_PARAMETER;
    502   }
    503 
    504   Instance = AllocatePool (sizeof (*Instance));
    505 
    506   if (Instance == NULL) {
    507     return EFI_OUT_OF_RESOURCES;
    508   }
    509 
    510   MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
    511 
    512   Mtftp4InitProtocol (MtftpSb, Instance);
    513 
    514   Instance->UnicastPort = UdpIoCreateIo (
    515                             MtftpSb->Controller,
    516                             MtftpSb->Image,
    517                             Mtftp4ConfigNullUdp,
    518                             UDP_IO_UDP4_VERSION,
    519                             Instance
    520                             );
    521 
    522   if (Instance->UnicastPort == NULL) {
    523     FreePool (Instance);
    524     return EFI_OUT_OF_RESOURCES;
    525   }
    526 
    527   //
    528   // Install the MTFTP protocol onto ChildHandle
    529   //
    530   Status = gBS->InstallMultipleProtocolInterfaces (
    531                   ChildHandle,
    532                   &gEfiMtftp4ProtocolGuid,
    533                   &Instance->Mtftp4,
    534                   NULL
    535                   );
    536 
    537   if (EFI_ERROR (Status)) {
    538     UdpIoFreeIo (Instance->UnicastPort);
    539     FreePool (Instance);
    540     return Status;
    541   }
    542 
    543   Instance->Handle  = *ChildHandle;
    544 
    545   //
    546   // Open the Udp4 protocol BY_CHILD.
    547   //
    548   Status = gBS->OpenProtocol (
    549                   MtftpSb->ConnectUdp->UdpHandle,
    550                   &gEfiUdp4ProtocolGuid,
    551                   (VOID **) &Udp4,
    552                   gMtftp4DriverBinding.DriverBindingHandle,
    553                   Instance->Handle,
    554                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    555                   );
    556   if (EFI_ERROR (Status)) {
    557     goto ON_ERROR;
    558   }
    559 
    560   //
    561   // Open the Udp4 protocol by child.
    562   //
    563   Status = gBS->OpenProtocol (
    564                   Instance->UnicastPort->UdpHandle,
    565                   &gEfiUdp4ProtocolGuid,
    566                   (VOID **) &Udp4,
    567                   gMtftp4DriverBinding.DriverBindingHandle,
    568                   Instance->Handle,
    569                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    570                   );
    571   if (EFI_ERROR (Status)) {
    572     //
    573     // Close the Udp4 protocol.
    574     //
    575     gBS->CloseProtocol (
    576            MtftpSb->ConnectUdp->UdpHandle,
    577            &gEfiUdp4ProtocolGuid,
    578            gMtftp4DriverBinding.DriverBindingHandle,
    579            ChildHandle
    580            );
    581     goto ON_ERROR;
    582   }
    583 
    584   //
    585   // Add it to the parent's child list.
    586   //
    587   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    588 
    589   InsertTailList (&MtftpSb->Children, &Instance->Link);
    590   MtftpSb->ChildrenNum++;
    591 
    592   gBS->RestoreTPL (OldTpl);
    593 
    594   return EFI_SUCCESS;
    595 
    596 ON_ERROR:
    597   if (Instance->Handle != NULL) {
    598     gBS->UninstallMultipleProtocolInterfaces (
    599            Instance->Handle,
    600            &gEfiMtftp4ProtocolGuid,
    601            &Instance->Mtftp4,
    602            NULL
    603            );
    604   }
    605 
    606   UdpIoFreeIo (Instance->UnicastPort);
    607   FreePool (Instance);
    608 
    609   return Status;
    610 }
    611 
    612 
    613 /**
    614   Destroy one of the service binding's child.
    615 
    616   @param  This                   The service binding instance
    617   @param  ChildHandle            The child handle to destroy
    618 
    619   @retval EFI_INVALID_PARAMETER  The parameter is invaid.
    620   @retval EFI_UNSUPPORTED        The child may have already been destroyed.
    621   @retval EFI_SUCCESS            The child is destroyed and removed from the
    622                                  parent's child list.
    623 
    624 **/
    625 EFI_STATUS
    626 EFIAPI
    627 Mtftp4ServiceBindingDestroyChild (
    628   IN EFI_SERVICE_BINDING_PROTOCOL *This,
    629   IN EFI_HANDLE                   ChildHandle
    630   )
    631 {
    632   MTFTP4_SERVICE            *MtftpSb;
    633   MTFTP4_PROTOCOL           *Instance;
    634   EFI_MTFTP4_PROTOCOL       *Mtftp4;
    635   EFI_STATUS                Status;
    636   EFI_TPL                   OldTpl;
    637 
    638   if ((This == NULL) || (ChildHandle == NULL)) {
    639     return EFI_INVALID_PARAMETER;
    640   }
    641 
    642   //
    643   // Retrieve the private context data structures
    644   //
    645   Status = gBS->OpenProtocol (
    646                   ChildHandle,
    647                   &gEfiMtftp4ProtocolGuid,
    648                   (VOID **) &Mtftp4,
    649                   gMtftp4DriverBinding.DriverBindingHandle,
    650                   ChildHandle,
    651                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    652                   );
    653 
    654   if (EFI_ERROR (Status)) {
    655     return EFI_UNSUPPORTED;
    656   }
    657 
    658   Instance  = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
    659   MtftpSb   = MTFTP4_SERVICE_FROM_THIS (This);
    660 
    661   if (Instance->Service != MtftpSb) {
    662     return EFI_INVALID_PARAMETER;
    663   }
    664 
    665   if (Instance->InDestroy) {
    666     return EFI_SUCCESS;
    667   }
    668 
    669   Instance->InDestroy = TRUE;
    670 
    671   //
    672   // Close the Udp4 protocol.
    673   //
    674   gBS->CloseProtocol (
    675          MtftpSb->ConnectUdp->UdpHandle,
    676          &gEfiUdp4ProtocolGuid,
    677          gMtftp4DriverBinding.DriverBindingHandle,
    678          ChildHandle
    679          );
    680 
    681   gBS->CloseProtocol (
    682          Instance->UnicastPort->UdpHandle,
    683          &gEfiUdp4ProtocolGuid,
    684          gMtftp4DriverBinding.DriverBindingHandle,
    685          ChildHandle
    686          );
    687 
    688   if (Instance->McastUdpPort != NULL) {
    689     gBS->CloseProtocol (
    690            Instance->McastUdpPort->UdpHandle,
    691            &gEfiUdp4ProtocolGuid,
    692            gMtftp4DriverBinding.DriverBindingHandle,
    693            ChildHandle
    694            );
    695   }
    696 
    697   //
    698   // Uninstall the MTFTP4 protocol first to enable a top down destruction.
    699   //
    700   Status = gBS->UninstallProtocolInterface (
    701                   ChildHandle,
    702                   &gEfiMtftp4ProtocolGuid,
    703                   Mtftp4
    704                   );
    705 
    706   if (EFI_ERROR (Status)) {
    707     Instance->InDestroy = FALSE;
    708     return Status;
    709   }
    710 
    711   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    712 
    713   Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
    714   UdpIoFreeIo (Instance->UnicastPort);
    715 
    716   RemoveEntryList (&Instance->Link);
    717   MtftpSb->ChildrenNum--;
    718 
    719   gBS->RestoreTPL (OldTpl);
    720 
    721   FreePool (Instance);
    722   return EFI_SUCCESS;
    723 }
    724