]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
1 /** @file
2 Implementation of Mtftp drivers.
3
4 Copyright (c) 2006 - 2018, 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->TimerNotifyLevel = NULL;
167 MtftpSb->TimerToGetMap = NULL;
168 MtftpSb->Controller = Controller;
169 MtftpSb->Image = Image;
170 MtftpSb->ConnectUdp = NULL;
171
172 //
173 // Create the timer and a udp to be notified when UDP is uninstalled
174 //
175 Status = gBS->CreateEvent (
176 EVT_NOTIFY_SIGNAL | EVT_TIMER,
177 TPL_CALLBACK,
178 Mtftp4OnTimerTick,
179 MtftpSb,
180 &MtftpSb->Timer
181 );
182 if (EFI_ERROR (Status)) {
183 FreePool (MtftpSb);
184 return Status;
185 }
186
187 Status = gBS->CreateEvent (
188 EVT_NOTIFY_SIGNAL | EVT_TIMER,
189 TPL_NOTIFY,
190 Mtftp4OnTimerTickNotifyLevel,
191 MtftpSb,
192 &MtftpSb->TimerNotifyLevel
193 );
194 if (EFI_ERROR (Status)) {
195 gBS->CloseEvent (MtftpSb->Timer);
196 FreePool (MtftpSb);
197 return Status;
198 }
199
200 //
201 // Create the timer used to time out the procedure which is used to
202 // get the default IP address.
203 //
204 Status = gBS->CreateEvent (
205 EVT_TIMER,
206 TPL_CALLBACK,
207 NULL,
208 NULL,
209 &MtftpSb->TimerToGetMap
210 );
211 if (EFI_ERROR (Status)) {
212 gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
213 gBS->CloseEvent (MtftpSb->Timer);
214 FreePool (MtftpSb);
215 return Status;
216 }
217
218 MtftpSb->ConnectUdp = UdpIoCreateIo (
219 Controller,
220 Image,
221 Mtftp4ConfigNullUdp,
222 UDP_IO_UDP4_VERSION,
223 NULL
224 );
225
226 if (MtftpSb->ConnectUdp == NULL) {
227 gBS->CloseEvent (MtftpSb->TimerToGetMap);
228 gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
229 gBS->CloseEvent (MtftpSb->Timer);
230 FreePool (MtftpSb);
231 return EFI_DEVICE_ERROR;
232 }
233
234 *Service = MtftpSb;
235 return EFI_SUCCESS;
236 }
237
238
239 /**
240 Release all the resource used the MTFTP service binding instance.
241
242 @param MtftpSb The MTFTP service binding instance.
243
244 **/
245 VOID
246 Mtftp4CleanService (
247 IN MTFTP4_SERVICE *MtftpSb
248 )
249 {
250 UdpIoFreeIo (MtftpSb->ConnectUdp);
251 gBS->CloseEvent (MtftpSb->TimerToGetMap);
252 gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
253 gBS->CloseEvent (MtftpSb->Timer);
254 }
255
256
257 /**
258 Start the MTFTP driver on this controller.
259
260 MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
261 controller, which can be used to create/destroy MTFTP children.
262
263 @param This The MTFTP driver binding protocol.
264 @param Controller The controller to manage.
265 @param RemainingDevicePath Remaining device path.
266
267 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
268 started on the controller.
269 @retval EFI_SUCCESS The MTFTP service binding is installed on the
270 controller.
271
272 **/
273 EFI_STATUS
274 EFIAPI
275 Mtftp4DriverBindingStart (
276 IN EFI_DRIVER_BINDING_PROTOCOL *This,
277 IN EFI_HANDLE Controller,
278 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
279 )
280 {
281 MTFTP4_SERVICE *MtftpSb;
282 EFI_STATUS Status;
283
284 //
285 // Directly return if driver is already running.
286 //
287 Status = gBS->OpenProtocol (
288 Controller,
289 &gEfiMtftp4ServiceBindingProtocolGuid,
290 NULL,
291 This->DriverBindingHandle,
292 Controller,
293 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
294 );
295
296 if (Status == EFI_SUCCESS) {
297 return EFI_ALREADY_STARTED;
298 }
299
300 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
301
302 if (EFI_ERROR (Status)) {
303 return Status;
304 }
305 ASSERT (MtftpSb != NULL);
306
307 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
308
309 if (EFI_ERROR (Status)) {
310 goto ON_ERROR;
311 }
312
313 Status = gBS->SetTimer (MtftpSb->TimerNotifyLevel, TimerPeriodic, TICKS_PER_SECOND);
314
315 if (EFI_ERROR (Status)) {
316 goto ON_ERROR;
317 }
318
319 //
320 // Install the Mtftp4ServiceBinding Protocol onto Controller
321 //
322 Status = gBS->InstallMultipleProtocolInterfaces (
323 &Controller,
324 &gEfiMtftp4ServiceBindingProtocolGuid,
325 &MtftpSb->ServiceBinding,
326 NULL
327 );
328
329 if (EFI_ERROR (Status)) {
330 goto ON_ERROR;
331 }
332
333 return EFI_SUCCESS;
334
335 ON_ERROR:
336 Mtftp4CleanService (MtftpSb);
337 FreePool (MtftpSb);
338
339 return Status;
340 }
341
342 /**
343 Callback function which provided by user to remove one node in NetDestroyLinkList process.
344
345 @param[in] Entry The entry to be removed.
346 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
347
348 @retval EFI_SUCCESS The entry has been removed successfully.
349 @retval Others Fail to remove the entry.
350
351 **/
352 EFI_STATUS
353 EFIAPI
354 Mtftp4DestroyChildEntryInHandleBuffer (
355 IN LIST_ENTRY *Entry,
356 IN VOID *Context
357 )
358 {
359 MTFTP4_PROTOCOL *Instance;
360 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
361 UINTN NumberOfChildren;
362 EFI_HANDLE *ChildHandleBuffer;
363
364 if (Entry == NULL || Context == NULL) {
365 return EFI_INVALID_PARAMETER;
366 }
367
368 Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP4_PROTOCOL, Link, MTFTP4_PROTOCOL_SIGNATURE);
369 ServiceBinding = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
370 NumberOfChildren = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
371 ChildHandleBuffer = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
372
373 if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
374 return EFI_SUCCESS;
375 }
376
377 return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
378 }
379
380 /**
381 Stop the MTFTP driver on controller. The controller is a UDP
382 child handle.
383
384 @param This The MTFTP driver binding protocol
385 @param Controller The controller to stop
386 @param NumberOfChildren The number of children
387 @param ChildHandleBuffer The array of the child handle.
388
389 @retval EFI_SUCCESS The driver is stopped on the controller.
390 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
391
392 **/
393 EFI_STATUS
394 EFIAPI
395 Mtftp4DriverBindingStop (
396 IN EFI_DRIVER_BINDING_PROTOCOL *This,
397 IN EFI_HANDLE Controller,
398 IN UINTN NumberOfChildren,
399 IN EFI_HANDLE *ChildHandleBuffer
400 )
401 {
402 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
403 MTFTP4_SERVICE *MtftpSb;
404 EFI_HANDLE NicHandle;
405 EFI_STATUS Status;
406 LIST_ENTRY *List;
407 MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
408
409 //
410 // MTFTP driver opens UDP child, So, Controller is a UDP
411 // child handle. Locate the Nic handle first. Then get the
412 // MTFTP private data back.
413 //
414 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
415
416 if (NicHandle == NULL) {
417 return EFI_SUCCESS;
418 }
419
420 Status = gBS->OpenProtocol (
421 NicHandle,
422 &gEfiMtftp4ServiceBindingProtocolGuid,
423 (VOID **) &ServiceBinding,
424 This->DriverBindingHandle,
425 NicHandle,
426 EFI_OPEN_PROTOCOL_GET_PROTOCOL
427 );
428
429 if (EFI_ERROR (Status)) {
430 return EFI_DEVICE_ERROR;
431 }
432
433 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
434
435 if (!IsListEmpty (&MtftpSb->Children)) {
436 //
437 // Destroy the Mtftp4 child instance in ChildHandleBuffer.
438 //
439 List = &MtftpSb->Children;
440 Context.ServiceBinding = ServiceBinding;
441 Context.NumberOfChildren = NumberOfChildren;
442 Context.ChildHandleBuffer = ChildHandleBuffer;
443 Status = NetDestroyLinkList (
444 List,
445 Mtftp4DestroyChildEntryInHandleBuffer,
446 &Context,
447 NULL
448 );
449 }
450
451 if (NumberOfChildren == 0 && IsListEmpty (&MtftpSb->Children)) {
452 gBS->UninstallProtocolInterface (
453 NicHandle,
454 &gEfiMtftp4ServiceBindingProtocolGuid,
455 ServiceBinding
456 );
457
458 Mtftp4CleanService (MtftpSb);
459 if (gMtftp4ControllerNameTable != NULL) {
460 FreeUnicodeStringTable (gMtftp4ControllerNameTable);
461 gMtftp4ControllerNameTable = NULL;
462 }
463 FreePool (MtftpSb);
464
465 Status = EFI_SUCCESS;
466 }
467
468 return Status;
469 }
470
471
472 /**
473 Initialize a MTFTP protocol instance which is the child of MtftpSb.
474
475 @param MtftpSb The MTFTP service binding protocol.
476 @param Instance The MTFTP instance to initialize.
477
478 **/
479 VOID
480 Mtftp4InitProtocol (
481 IN MTFTP4_SERVICE *MtftpSb,
482 OUT MTFTP4_PROTOCOL *Instance
483 )
484 {
485 ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
486
487 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
488 InitializeListHead (&Instance->Link);
489 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
490 Instance->State = MTFTP4_STATE_UNCONFIGED;
491 Instance->Service = MtftpSb;
492
493 InitializeListHead (&Instance->Blocks);
494 }
495
496
497 /**
498 Create a MTFTP child for the service binding instance, then
499 install the MTFTP protocol to the ChildHandle.
500
501 @param This The MTFTP service binding instance.
502 @param ChildHandle The Child handle to install the MTFTP protocol.
503
504 @retval EFI_INVALID_PARAMETER The parameter is invalid.
505 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
506 @retval EFI_SUCCESS The child is successfully create.
507
508 **/
509 EFI_STATUS
510 EFIAPI
511 Mtftp4ServiceBindingCreateChild (
512 IN EFI_SERVICE_BINDING_PROTOCOL *This,
513 IN EFI_HANDLE *ChildHandle
514 )
515 {
516 MTFTP4_SERVICE *MtftpSb;
517 MTFTP4_PROTOCOL *Instance;
518 EFI_STATUS Status;
519 EFI_TPL OldTpl;
520 VOID *Udp4;
521
522 if ((This == NULL) || (ChildHandle == NULL)) {
523 return EFI_INVALID_PARAMETER;
524 }
525
526 Instance = AllocatePool (sizeof (*Instance));
527
528 if (Instance == NULL) {
529 return EFI_OUT_OF_RESOURCES;
530 }
531
532 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
533
534 Mtftp4InitProtocol (MtftpSb, Instance);
535
536 Instance->UnicastPort = UdpIoCreateIo (
537 MtftpSb->Controller,
538 MtftpSb->Image,
539 Mtftp4ConfigNullUdp,
540 UDP_IO_UDP4_VERSION,
541 Instance
542 );
543
544 if (Instance->UnicastPort == NULL) {
545 FreePool (Instance);
546 return EFI_OUT_OF_RESOURCES;
547 }
548
549 //
550 // Install the MTFTP protocol onto ChildHandle
551 //
552 Status = gBS->InstallMultipleProtocolInterfaces (
553 ChildHandle,
554 &gEfiMtftp4ProtocolGuid,
555 &Instance->Mtftp4,
556 NULL
557 );
558
559 if (EFI_ERROR (Status)) {
560 UdpIoFreeIo (Instance->UnicastPort);
561 FreePool (Instance);
562 return Status;
563 }
564
565 Instance->Handle = *ChildHandle;
566
567 //
568 // Open the Udp4 protocol BY_CHILD.
569 //
570 Status = gBS->OpenProtocol (
571 MtftpSb->ConnectUdp->UdpHandle,
572 &gEfiUdp4ProtocolGuid,
573 (VOID **) &Udp4,
574 gMtftp4DriverBinding.DriverBindingHandle,
575 Instance->Handle,
576 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
577 );
578 if (EFI_ERROR (Status)) {
579 goto ON_ERROR;
580 }
581
582 //
583 // Open the Udp4 protocol by child.
584 //
585 Status = gBS->OpenProtocol (
586 Instance->UnicastPort->UdpHandle,
587 &gEfiUdp4ProtocolGuid,
588 (VOID **) &Udp4,
589 gMtftp4DriverBinding.DriverBindingHandle,
590 Instance->Handle,
591 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
592 );
593 if (EFI_ERROR (Status)) {
594 //
595 // Close the Udp4 protocol.
596 //
597 gBS->CloseProtocol (
598 MtftpSb->ConnectUdp->UdpHandle,
599 &gEfiUdp4ProtocolGuid,
600 gMtftp4DriverBinding.DriverBindingHandle,
601 ChildHandle
602 );
603 goto ON_ERROR;
604 }
605
606 //
607 // Add it to the parent's child list.
608 //
609 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
610
611 InsertTailList (&MtftpSb->Children, &Instance->Link);
612 MtftpSb->ChildrenNum++;
613
614 gBS->RestoreTPL (OldTpl);
615
616 return EFI_SUCCESS;
617
618 ON_ERROR:
619 if (Instance->Handle != NULL) {
620 gBS->UninstallMultipleProtocolInterfaces (
621 Instance->Handle,
622 &gEfiMtftp4ProtocolGuid,
623 &Instance->Mtftp4,
624 NULL
625 );
626 }
627
628 UdpIoFreeIo (Instance->UnicastPort);
629 FreePool (Instance);
630
631 return Status;
632 }
633
634
635 /**
636 Destroy one of the service binding's child.
637
638 @param This The service binding instance
639 @param ChildHandle The child handle to destroy
640
641 @retval EFI_INVALID_PARAMETER The parameter is invaid.
642 @retval EFI_UNSUPPORTED The child may have already been destroyed.
643 @retval EFI_SUCCESS The child is destroyed and removed from the
644 parent's child list.
645
646 **/
647 EFI_STATUS
648 EFIAPI
649 Mtftp4ServiceBindingDestroyChild (
650 IN EFI_SERVICE_BINDING_PROTOCOL *This,
651 IN EFI_HANDLE ChildHandle
652 )
653 {
654 MTFTP4_SERVICE *MtftpSb;
655 MTFTP4_PROTOCOL *Instance;
656 EFI_MTFTP4_PROTOCOL *Mtftp4;
657 EFI_STATUS Status;
658 EFI_TPL OldTpl;
659
660 if ((This == NULL) || (ChildHandle == NULL)) {
661 return EFI_INVALID_PARAMETER;
662 }
663
664 //
665 // Retrieve the private context data structures
666 //
667 Status = gBS->OpenProtocol (
668 ChildHandle,
669 &gEfiMtftp4ProtocolGuid,
670 (VOID **) &Mtftp4,
671 gMtftp4DriverBinding.DriverBindingHandle,
672 ChildHandle,
673 EFI_OPEN_PROTOCOL_GET_PROTOCOL
674 );
675
676 if (EFI_ERROR (Status)) {
677 return EFI_UNSUPPORTED;
678 }
679
680 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
681 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
682
683 if (Instance->Service != MtftpSb) {
684 return EFI_INVALID_PARAMETER;
685 }
686
687 if (Instance->InDestroy) {
688 return EFI_SUCCESS;
689 }
690
691 Instance->InDestroy = TRUE;
692
693 //
694 // Close the Udp4 protocol.
695 //
696 gBS->CloseProtocol (
697 MtftpSb->ConnectUdp->UdpHandle,
698 &gEfiUdp4ProtocolGuid,
699 gMtftp4DriverBinding.DriverBindingHandle,
700 ChildHandle
701 );
702
703 gBS->CloseProtocol (
704 Instance->UnicastPort->UdpHandle,
705 &gEfiUdp4ProtocolGuid,
706 gMtftp4DriverBinding.DriverBindingHandle,
707 ChildHandle
708 );
709
710 if (Instance->McastUdpPort != NULL) {
711 gBS->CloseProtocol (
712 Instance->McastUdpPort->UdpHandle,
713 &gEfiUdp4ProtocolGuid,
714 gMtftp4DriverBinding.DriverBindingHandle,
715 ChildHandle
716 );
717 }
718
719 //
720 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
721 //
722 Status = gBS->UninstallProtocolInterface (
723 ChildHandle,
724 &gEfiMtftp4ProtocolGuid,
725 Mtftp4
726 );
727
728 if (EFI_ERROR (Status)) {
729 Instance->InDestroy = FALSE;
730 return Status;
731 }
732
733 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
734
735 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
736 UdpIoFreeIo (Instance->UnicastPort);
737
738 RemoveEntryList (&Instance->Link);
739 MtftpSb->ChildrenNum--;
740
741 gBS->RestoreTPL (OldTpl);
742
743 FreePool (Instance);
744 return EFI_SUCCESS;
745 }