1 /** @file
2   Driver Binding functions and Service Binding functions
3   implementation for Mtftp6 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 "Mtftp6Impl.h"
18 
19 
20 EFI_DRIVER_BINDING_PROTOCOL   gMtftp6DriverBinding = {
21   Mtftp6DriverBindingSupported,
22   Mtftp6DriverBindingStart,
23   Mtftp6DriverBindingStop,
24   0xa,
25   NULL,
26   NULL
27 };
28 
29 EFI_SERVICE_BINDING_PROTOCOL  gMtftp6ServiceBindingTemplate = {
30   Mtftp6ServiceBindingCreateChild,
31   Mtftp6ServiceBindingDestroyChild
32 };
33 
34 
35 /**
36   Destroy the MTFTP6 service. The MTFTP6 service may be partly initialized,
37   or partly destroyed. If a resource is destroyed, it is marked as such in
38   case the destroy failed and is called again later.
39 
40   @param[in]  Service            The MTFTP6 service to be destroyed.
41 
42 **/
43 VOID
Mtftp6DestroyService(IN MTFTP6_SERVICE * Service)44 Mtftp6DestroyService (
45   IN MTFTP6_SERVICE     *Service
46   )
47 {
48   //
49   // Make sure all children instances have been already destroyed.
50   //
51   ASSERT (Service->ChildrenNum == 0);
52 
53   if (Service->DummyUdpIo != NULL) {
54     UdpIoFreeIo (Service->DummyUdpIo);
55   }
56 
57   if (Service->Timer != NULL) {
58     gBS->CloseEvent (Service->Timer);
59   }
60 
61   FreePool (Service);
62 }
63 
64 
65 /**
66   Create then initialize a MTFTP6 service binding instance.
67 
68   @param[in]  Controller             The controller to install the MTFTP6 service
69                                      binding on.
70   @param[in]  Image                  The driver binding image of the MTFTP6 driver.
71   @param[out] Service                The variable to receive the created service
72                                      binding instance.
73 
74   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources to create the instance
75   @retval EFI_DEVICE_ERROR       Failed to create a NULL UDP port to keep connection with UDP.
76   @retval EFI_SUCCESS            The service instance is created for the controller.
77 
78 **/
79 EFI_STATUS
Mtftp6CreateService(IN EFI_HANDLE Controller,IN EFI_HANDLE Image,OUT MTFTP6_SERVICE ** Service)80 Mtftp6CreateService (
81   IN  EFI_HANDLE            Controller,
82   IN  EFI_HANDLE            Image,
83   OUT MTFTP6_SERVICE        **Service
84   )
85 {
86   MTFTP6_SERVICE            *Mtftp6Srv;
87   EFI_STATUS                Status;
88 
89   ASSERT (Service != NULL);
90 
91   *Service  = NULL;
92   Mtftp6Srv = AllocateZeroPool (sizeof (MTFTP6_SERVICE));
93 
94   if (Mtftp6Srv == NULL) {
95     return EFI_OUT_OF_RESOURCES;
96   }
97 
98   Mtftp6Srv->Signature      = MTFTP6_SERVICE_SIGNATURE;
99   Mtftp6Srv->Controller     = Controller;
100   Mtftp6Srv->Image          = Image;
101   Mtftp6Srv->ChildrenNum    = 0;
102 
103   CopyMem (
104     &Mtftp6Srv->ServiceBinding,
105     &gMtftp6ServiceBindingTemplate,
106     sizeof (EFI_SERVICE_BINDING_PROTOCOL)
107     );
108 
109   InitializeListHead (&Mtftp6Srv->Children);
110 
111   //
112   // Create a internal timer for all instances.
113   //
114   Status = gBS->CreateEvent (
115                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
116                   TPL_CALLBACK,
117                   Mtftp6OnTimerTick,
118                   Mtftp6Srv,
119                   &Mtftp6Srv->Timer
120                   );
121 
122   if (EFI_ERROR (Status)) {
123     FreePool (Mtftp6Srv);
124     return Status;
125   }
126 
127   //
128   // Create a dummy Udp6Io to build parent-child relationship between Udp6 driver
129   // and Mtftp6 driver.
130   //
131   Mtftp6Srv->DummyUdpIo = UdpIoCreateIo (
132                             Controller,
133                             Image,
134                             Mtftp6ConfigDummyUdpIo,
135                             UDP_IO_UDP6_VERSION,
136                             NULL
137                             );
138 
139   if (Mtftp6Srv->DummyUdpIo == NULL) {
140     gBS->CloseEvent (Mtftp6Srv->Timer);
141     FreePool (Mtftp6Srv);
142     return EFI_DEVICE_ERROR;
143   }
144 
145   *Service = Mtftp6Srv;
146   return EFI_SUCCESS;
147 }
148 
149 
150 /**
151   Destroy the MTFTP6 instance and recycle the resources.
152 
153   @param[in]  Instance        The pointer to the MTFTP6 instance.
154 
155 **/
156 VOID
Mtftp6DestroyInstance(IN MTFTP6_INSTANCE * Instance)157 Mtftp6DestroyInstance (
158   IN MTFTP6_INSTANCE         *Instance
159   )
160 {
161   LIST_ENTRY                 *Entry;
162   LIST_ENTRY                 *Next;
163   MTFTP6_BLOCK_RANGE         *Block;
164 
165   if (Instance->Config != NULL) {
166     FreePool (Instance->Config);
167   }
168 
169   if (Instance->Token != NULL && Instance->Token->Event != NULL) {
170     gBS->SignalEvent (Instance->Token->Event);
171   }
172 
173   if (Instance->LastPacket != NULL) {
174     NetbufFree (Instance->LastPacket);
175   }
176 
177   if (Instance->UdpIo!= NULL) {
178     UdpIoFreeIo (Instance->UdpIo);
179   }
180 
181   if (Instance->McastUdpIo != NULL) {
182     UdpIoFreeIo (Instance->McastUdpIo);
183   }
184 
185   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
186     Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
187     RemoveEntryList (Entry);
188     FreePool (Block);
189   }
190 
191   FreePool (Instance);
192 }
193 
194 
195 /**
196   Create the MTFTP6 instance and initialize it.
197 
198   @param[in]  Service              The pointer to the MTFTP6 service.
199   @param[out] Instance             The pointer to the MTFTP6 instance.
200 
201   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
202   @retval EFI_SUCCESS            The MTFTP6 instance is created.
203 
204 **/
205 EFI_STATUS
Mtftp6CreateInstance(IN MTFTP6_SERVICE * Service,OUT MTFTP6_INSTANCE ** Instance)206 Mtftp6CreateInstance (
207   IN  MTFTP6_SERVICE         *Service,
208   OUT MTFTP6_INSTANCE        **Instance
209   )
210 {
211   MTFTP6_INSTANCE            *Mtftp6Ins;
212 
213   *Instance = NULL;
214   Mtftp6Ins = AllocateZeroPool (sizeof (MTFTP6_INSTANCE));
215 
216   if (Mtftp6Ins == NULL) {
217     return EFI_OUT_OF_RESOURCES;
218   }
219 
220   Mtftp6Ins->Signature = MTFTP6_INSTANCE_SIGNATURE;
221   Mtftp6Ins->InDestroy = FALSE;
222   Mtftp6Ins->Service   = Service;
223 
224   CopyMem (
225     &Mtftp6Ins->Mtftp6,
226     &gMtftp6ProtocolTemplate,
227     sizeof (EFI_MTFTP6_PROTOCOL)
228     );
229 
230   InitializeListHead (&Mtftp6Ins->Link);
231   InitializeListHead (&Mtftp6Ins->BlkList);
232 
233   *Instance = Mtftp6Ins;
234 
235   return EFI_SUCCESS;
236 }
237 
238 
239 /**
240   Callback function which provided by user to remove one node in NetDestroyLinkList process.
241 
242   @param[in]    Entry           The entry to be removed.
243   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
244 
245   @retval EFI_SUCCESS           The entry has been removed successfully.
246   @retval Others                Fail to remove the entry.
247 
248 **/
249 EFI_STATUS
250 EFIAPI
Mtftp6DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)251 Mtftp6DestroyChildEntryInHandleBuffer (
252   IN LIST_ENTRY         *Entry,
253   IN VOID               *Context
254   )
255 {
256   MTFTP6_INSTANCE               *Instance;
257   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
258   UINTN                         NumberOfChildren;
259   EFI_HANDLE                    *ChildHandleBuffer;
260 
261   if (Entry == NULL || Context == NULL) {
262     return EFI_INVALID_PARAMETER;
263   }
264 
265   Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP6_INSTANCE, Link, MTFTP6_INSTANCE_SIGNATURE);
266   ServiceBinding    = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
267   NumberOfChildren  = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
268   ChildHandleBuffer = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
269 
270   if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
271     return EFI_SUCCESS;
272   }
273 
274   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
275 }
276 
277 
278 /**
279   This is the declaration of an EFI image entry point. This entry point is
280   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
281   both device drivers and bus drivers.
282 
283   Entry point of the MTFTP6 driver to install various protocols.
284 
285   @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
286   @param[in]  SystemTable           The pointer to the EFI System Table.
287 
288   @retval EFI_SUCCESS           The operation completed successfully.
289   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
290 
291 **/
292 EFI_STATUS
293 EFIAPI
Mtftp6DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)294 Mtftp6DriverEntryPoint (
295   IN EFI_HANDLE             ImageHandle,
296   IN EFI_SYSTEM_TABLE       *SystemTable
297   )
298 {
299   return EfiLibInstallDriverBindingComponentName2 (
300            ImageHandle,
301            SystemTable,
302            &gMtftp6DriverBinding,
303            ImageHandle,
304            &gMtftp6ComponentName,
305            &gMtftp6ComponentName2
306            );
307 }
308 
309 
310 /**
311   Test to see if this driver supports Controller. This service
312   is called by the EFI boot service ConnectController(). In
313   order to make drivers as small as possible, there are calling
314   restrictions for this service. ConnectController() must
315   follow these calling restrictions. If any other agent wishes to call
316   Supported(), it must also follow these calling restrictions.
317 
318   @param[in]  This                Protocol instance pointer.
319   @param[in]  Controller          Handle of device to test
320   @param[in]  RemainingDevicePath Optional parameter use to pick a specific child.
321                                   device to start.
322 
323   @retval EFI_SUCCESS         This driver supports this device.
324   @retval Others              This driver does not support this device.
325 
326 **/
327 EFI_STATUS
328 EFIAPI
Mtftp6DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)329 Mtftp6DriverBindingSupported (
330   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
331   IN EFI_HANDLE                     Controller,
332   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
333   )
334 {
335   return gBS->OpenProtocol (
336                 Controller,
337                 &gEfiUdp6ServiceBindingProtocolGuid,
338                 NULL,
339                 This->DriverBindingHandle,
340                 Controller,
341                 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
342                 );
343 }
344 
345 
346 /**
347   Start this driver on Controller. This service is called by the
348   EFI boot service ConnectController(). In order to make
349   drivers as small as possible, there are calling restrictions for
350   this service. ConnectController() must follow these
351   calling restrictions. If any other agent wishes to call Start() it
352   must also follow these calling restrictions.
353 
354   @param[in]  This                 Protocol instance pointer.
355   @param[in]  Controller           Handle of device to bind driver to.
356   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
357                                    device to start.
358 
359   @retval EFI_SUCCESS          This driver is added to Controller.
360   @retval EFI_ALREADY_STARTED  This driver is already running on Controller.
361   @retval Others               This driver does not support this device.
362 
363 **/
364 EFI_STATUS
365 EFIAPI
Mtftp6DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)366 Mtftp6DriverBindingStart (
367   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
368   IN EFI_HANDLE                   Controller,
369   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
370   )
371 {
372   MTFTP6_SERVICE            *Service;
373   EFI_STATUS                Status;
374 
375   //
376   // Directly return if driver is already running on this Nic handle.
377   //
378   Status = gBS->OpenProtocol (
379                   Controller,
380                   &gEfiMtftp6ServiceBindingProtocolGuid,
381                   NULL,
382                   This->DriverBindingHandle,
383                   Controller,
384                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
385                   );
386 
387   if (!EFI_ERROR (Status)) {
388     return EFI_ALREADY_STARTED;
389   }
390 
391   //
392   // Create Mtftp6 service for this Nic handle
393   //
394   Status = Mtftp6CreateService (
395              Controller,
396              This->DriverBindingHandle,
397              &Service
398              );
399 
400   if (EFI_ERROR (Status)) {
401     return Status;
402   }
403 
404   ASSERT (Service != NULL);
405 
406   //
407   // Start the internal timer to track the packet retransmission.
408   //
409   Status = gBS->SetTimer (
410                   Service->Timer,
411                   TimerPeriodic,
412                   TICKS_PER_SECOND
413                   );
414 
415   if (EFI_ERROR (Status)) {
416     goto ON_ERROR;
417   }
418 
419   //
420   // Install the Mtftp6 service on the Nic handle.
421   //
422   Status = gBS->InstallMultipleProtocolInterfaces (
423                   &Controller,
424                   &gEfiMtftp6ServiceBindingProtocolGuid,
425                   &Service->ServiceBinding,
426                   NULL
427                   );
428 
429   if (EFI_ERROR (Status)) {
430     goto ON_ERROR;
431   }
432 
433   return EFI_SUCCESS;
434 
435 ON_ERROR:
436 
437   Mtftp6DestroyService (Service);
438   return Status;
439 }
440 
441 
442 /**
443   Stop this driver on Controller. This service is called by the
444   EFI boot service DisconnectController(). In order to
445   make drivers as small as possible, there are calling
446   restrictions for this service. DisconnectController()
447   must follow these calling restrictions. If any other agent wishes
448   to call Stop(), it must also follow these calling restrictions.
449 
450   @param[in]  This              Protocol instance pointer.
451   @param[in]  Controller        Handle of device to stop driver on
452   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
453                                 children is zero, stop the entire bus driver.
454   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
455 
456   @retval EFI_SUCCESS       This driver is removed Controller.
457   @retval EFI_DEVICE_ERROR  An unexpected error.
458   @retval Others            This driver was not removed from this device.
459 
460 **/
461 EFI_STATUS
462 EFIAPI
Mtftp6DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)463 Mtftp6DriverBindingStop (
464   IN  EFI_DRIVER_BINDING_PROTOCOL *This,
465   IN  EFI_HANDLE                  Controller,
466   IN  UINTN                       NumberOfChildren,
467   IN  EFI_HANDLE                  *ChildHandleBuffer
468   )
469 {
470   EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;
471   MTFTP6_SERVICE                             *Service;
472   EFI_HANDLE                                 NicHandle;
473   EFI_STATUS                                 Status;
474   LIST_ENTRY                                 *List;
475   MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
476 
477   //
478   // Locate the Nic handle to retrieve the Mtftp6 private data.
479   //
480   NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp6ProtocolGuid);
481 
482   if (NicHandle == NULL) {
483     return EFI_SUCCESS;
484   }
485 
486   Status = gBS->OpenProtocol (
487                   NicHandle,
488                   &gEfiMtftp6ServiceBindingProtocolGuid,
489                   (VOID **) &ServiceBinding,
490                   This->DriverBindingHandle,
491                   NicHandle,
492                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
493                   );
494 
495   if (EFI_ERROR (Status)) {
496     return EFI_DEVICE_ERROR;
497   }
498 
499   Service = MTFTP6_SERVICE_FROM_THIS (ServiceBinding);
500 
501   if (!IsListEmpty (&Service->Children)) {
502     //
503     // Destroy the Mtftp6 child instance in ChildHandleBuffer.
504     //
505     List = &Service->Children;
506     Context.ServiceBinding    = ServiceBinding;
507     Context.NumberOfChildren  = NumberOfChildren;
508     Context.ChildHandleBuffer = ChildHandleBuffer;
509     Status = NetDestroyLinkList (
510                List,
511                Mtftp6DestroyChildEntryInHandleBuffer,
512                &Context,
513                NULL
514                );
515   }
516 
517   if (NumberOfChildren == 0 && IsListEmpty (&Service->Children)) {
518     //
519     // Destroy the Mtftp6 service if there is no Mtftp6 child instance left.
520     //
521     gBS->UninstallProtocolInterface (
522            NicHandle,
523            &gEfiMtftp6ServiceBindingProtocolGuid,
524            ServiceBinding
525            );
526 
527     Mtftp6DestroyService (Service);
528     Status = EFI_SUCCESS;
529   }
530 
531   return Status;
532 }
533 
534 
535 /**
536   Creates a child handle and installs a protocol.
537 
538   The CreateChild() function installs a protocol on ChildHandle.
539   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
540   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
541 
542   @param[in]      This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
543   @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL,
544                               then a new handle is created. If it is a pointer to an existing
545                               UEFI handle, then the protocol is added to the existing UEFI handle.
546 
547   @retval EFI_SUCCES            The protocol was added to ChildHandle.
548   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
549   @retval Others                The child handle was not created.
550 
551 **/
552 EFI_STATUS
553 EFIAPI
Mtftp6ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN OUT EFI_HANDLE * ChildHandle)554 Mtftp6ServiceBindingCreateChild (
555   IN     EFI_SERVICE_BINDING_PROTOCOL  *This,
556   IN OUT EFI_HANDLE                    *ChildHandle
557   )
558 {
559   MTFTP6_SERVICE            *Service;
560   MTFTP6_INSTANCE           *Instance;
561   EFI_STATUS                Status;
562   EFI_TPL                   OldTpl;
563   VOID                      *Udp6;
564 
565   if (This == NULL || ChildHandle == NULL) {
566     return EFI_INVALID_PARAMETER;
567   }
568 
569   Service = MTFTP6_SERVICE_FROM_THIS (This);
570 
571   Status = Mtftp6CreateInstance (Service, &Instance);
572 
573   if (EFI_ERROR (Status)) {
574     return Status;
575   }
576 
577   ASSERT (Instance != NULL);
578 
579   //
580   // Install the Mtftp6 protocol on the new child handle.
581   //
582   Status = gBS->InstallMultipleProtocolInterfaces (
583                   ChildHandle,
584                   &gEfiMtftp6ProtocolGuid,
585                   &Instance->Mtftp6,
586                   NULL
587                   );
588 
589   if (EFI_ERROR (Status)) {
590     goto ON_ERROR;
591   }
592 
593   Instance->Handle = *ChildHandle;
594 
595   //
596   // Open the Udp6 protocol by child.
597   //
598   Status = gBS->OpenProtocol (
599                   Service->DummyUdpIo->UdpHandle,
600                   &gEfiUdp6ProtocolGuid,
601                   (VOID **) &Udp6,
602                   gMtftp6DriverBinding.DriverBindingHandle,
603                   Instance->Handle,
604                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
605                   );
606 
607   if (EFI_ERROR (Status)) {
608     gBS->UninstallMultipleProtocolInterfaces (
609            Instance->Handle,
610            &gEfiMtftp6ProtocolGuid,
611            &Instance->Mtftp6,
612            NULL
613            );
614 
615     goto ON_ERROR;
616   }
617 
618   //
619   // Add the new Mtftp6 instance into the children list of Mtftp6 service.
620   //
621   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
622 
623   InsertTailList (&Service->Children, &Instance->Link);
624   Service->ChildrenNum++;
625 
626   gBS->RestoreTPL (OldTpl);
627   return EFI_SUCCESS;
628 
629 ON_ERROR:
630 
631   Mtftp6DestroyInstance (Instance);
632   return Status;
633 }
634 
635 
636 /**
637   Destroys a child handle with a protocol installed on it.
638 
639   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
640   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
641   last protocol on ChildHandle, then ChildHandle is destroyed.
642 
643   @param[in]  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
644   @param[in]  ChildHandle Handle of the child to destroy.
645 
646   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
647   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
648   @retval EFI_INVALID_PARAMETER Child handle is NULL.
649   @retval Others                The child handle was not destroyed
650 
651 **/
652 EFI_STATUS
653 EFIAPI
Mtftp6ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)654 Mtftp6ServiceBindingDestroyChild (
655   IN EFI_SERVICE_BINDING_PROTOCOL *This,
656   IN EFI_HANDLE                   ChildHandle
657   )
658 {
659   MTFTP6_SERVICE            *Service;
660   MTFTP6_INSTANCE           *Instance;
661   EFI_MTFTP6_PROTOCOL       *Mtftp6;
662   EFI_STATUS                Status;
663   EFI_TPL                   OldTpl;
664 
665   if (This == NULL || ChildHandle == NULL) {
666     return EFI_INVALID_PARAMETER;
667   }
668 
669   //
670   // Locate the Nic handle to retrieve the Mtftp6 private data.
671   //
672   Status = gBS->OpenProtocol (
673                   ChildHandle,
674                   &gEfiMtftp6ProtocolGuid,
675                   (VOID **) &Mtftp6,
676                   gMtftp6DriverBinding.DriverBindingHandle,
677                   ChildHandle,
678                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
679                   );
680 
681   if (EFI_ERROR (Status)) {
682     return EFI_UNSUPPORTED;
683   }
684 
685   Instance = MTFTP6_INSTANCE_FROM_THIS (Mtftp6);
686   Service  = MTFTP6_SERVICE_FROM_THIS (This);
687 
688   if (Instance->Service != Service) {
689     return EFI_INVALID_PARAMETER;
690   }
691 
692   //
693   // Check whether the instance already in Destroy state.
694   //
695   if (Instance->InDestroy) {
696     return EFI_SUCCESS;
697   }
698 
699   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
700 
701   Instance->InDestroy = TRUE;
702 
703   gBS->CloseProtocol (
704          Service->DummyUdpIo->UdpHandle,
705          &gEfiUdp6ProtocolGuid,
706          gMtftp6DriverBinding.DriverBindingHandle,
707          ChildHandle
708          );
709 
710   if (Instance->UdpIo != NULL) {
711     gBS->CloseProtocol (
712          Instance->UdpIo->UdpHandle,
713          &gEfiUdp6ProtocolGuid,
714          gMtftp6DriverBinding.DriverBindingHandle,
715          Instance->Handle
716          );
717   }
718 
719   if (Instance->McastUdpIo != NULL) {
720     gBS->CloseProtocol (
721            Instance->McastUdpIo->UdpHandle,
722            &gEfiUdp6ProtocolGuid,
723            gMtftp6DriverBinding.DriverBindingHandle,
724            Instance->Handle
725            );
726   }
727 
728   //
729   // Uninstall the MTFTP6 protocol first to enable a top down destruction.
730   //
731   gBS->RestoreTPL (OldTpl);
732   Status = gBS->UninstallProtocolInterface (
733                   ChildHandle,
734                   &gEfiMtftp6ProtocolGuid,
735                   Mtftp6
736                   );
737   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
738   if (EFI_ERROR (Status)) {
739     Instance->InDestroy = FALSE;
740     gBS->RestoreTPL (OldTpl);
741     return Status;
742   }
743 
744   //
745   // Remove the Mtftp6 instance from the children list of Mtftp6 service.
746   //
747   RemoveEntryList (&Instance->Link);
748   Service->ChildrenNum --;
749 
750   gBS->RestoreTPL (OldTpl);
751 
752   Mtftp6DestroyInstance (Instance);
753 
754   return EFI_SUCCESS;
755 }
756