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