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