• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Mtftp4DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
Mtftp4DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
Mtftp4ConfigNullUdp(IN UDP_IO * UdpIo,IN VOID * Context)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
Mtftp4CreateService(IN EFI_HANDLE Controller,IN EFI_HANDLE Image,OUT MTFTP4_SERVICE ** Service)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
Mtftp4CleanService(IN MTFTP4_SERVICE * MtftpSb)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
Mtftp4DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
Mtftp4DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)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
Mtftp4DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
Mtftp4InitProtocol(IN MTFTP4_SERVICE * MtftpSb,OUT MTFTP4_PROTOCOL * Instance)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
Mtftp4ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE * ChildHandle)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
Mtftp4ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)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