]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Mtftp6Dxe/Mtftp6Driver.c
1. Add EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName() support.
[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 - 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
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
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
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
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 Mtftp6DestroyChildEntryInHandleBuffer (
251 IN LIST_ENTRY *Entry,
252 IN VOID *Context
253 )
254 {
255 MTFTP6_INSTANCE *Instance;
256 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
257 UINTN NumberOfChildren;
258 EFI_HANDLE *ChildHandleBuffer;
259
260 if (Entry == NULL || Context == NULL) {
261 return EFI_INVALID_PARAMETER;
262 }
263
264 Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP6_INSTANCE, Link, MTFTP6_INSTANCE_SIGNATURE);
265 ServiceBinding = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
266 NumberOfChildren = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
267 ChildHandleBuffer = ((MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
268
269 if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
270 return EFI_SUCCESS;
271 }
272
273 return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
274 }
275
276
277 /**
278 This is the declaration of an EFI image entry point. This entry point is
279 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
280 both device drivers and bus drivers.
281
282 Entry point of the MTFTP6 driver to install various protocols.
283
284 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
285 @param[in] SystemTable The pointer to the EFI System Table.
286
287 @retval EFI_SUCCESS The operation completed successfully.
288 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
289
290 **/
291 EFI_STATUS
292 EFIAPI
293 Mtftp6DriverEntryPoint (
294 IN EFI_HANDLE ImageHandle,
295 IN EFI_SYSTEM_TABLE *SystemTable
296 )
297 {
298 return EfiLibInstallDriverBindingComponentName2 (
299 ImageHandle,
300 SystemTable,
301 &gMtftp6DriverBinding,
302 ImageHandle,
303 &gMtftp6ComponentName,
304 &gMtftp6ComponentName2
305 );
306 }
307
308
309 /**
310 Test to see if this driver supports Controller. This service
311 is called by the EFI boot service ConnectController(). In
312 order to make drivers as small as possible, there are calling
313 restrictions for this service. ConnectController() must
314 follow these calling restrictions. If any other agent wishes to call
315 Supported(), it must also follow these calling restrictions.
316
317 @param[in] This Protocol instance pointer.
318 @param[in] Controller Handle of device to test
319 @param[in] RemainingDevicePath Optional parameter use to pick a specific child.
320 device to start.
321
322 @retval EFI_SUCCESS This driver supports this device.
323 @retval Others This driver does not support this device.
324
325 **/
326 EFI_STATUS
327 EFIAPI
328 Mtftp6DriverBindingSupported (
329 IN EFI_DRIVER_BINDING_PROTOCOL *This,
330 IN EFI_HANDLE Controller,
331 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
332 )
333 {
334 return gBS->OpenProtocol (
335 Controller,
336 &gEfiUdp6ServiceBindingProtocolGuid,
337 NULL,
338 This->DriverBindingHandle,
339 Controller,
340 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
341 );
342 }
343
344
345 /**
346 Start this driver on Controller. This service is called by the
347 EFI boot service ConnectController(). In order to make
348 drivers as small as possible, there are calling restrictions for
349 this service. ConnectController() must follow these
350 calling restrictions. If any other agent wishes to call Start() it
351 must also follow these calling restrictions.
352
353 @param[in] This Protocol instance pointer.
354 @param[in] Controller Handle of device to bind driver to.
355 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
356 device to start.
357
358 @retval EFI_SUCCESS This driver is added to Controller.
359 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
360 @retval Others This driver does not support this device.
361
362 **/
363 EFI_STATUS
364 EFIAPI
365 Mtftp6DriverBindingStart (
366 IN EFI_DRIVER_BINDING_PROTOCOL *This,
367 IN EFI_HANDLE Controller,
368 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
369 )
370 {
371 MTFTP6_SERVICE *Service;
372 EFI_STATUS Status;
373
374 //
375 // Directly return if driver is already running on this Nic handle.
376 //
377 Status = gBS->OpenProtocol (
378 Controller,
379 &gEfiMtftp6ServiceBindingProtocolGuid,
380 NULL,
381 This->DriverBindingHandle,
382 Controller,
383 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
384 );
385
386 if (!EFI_ERROR (Status)) {
387 return EFI_ALREADY_STARTED;
388 }
389
390 //
391 // Create Mtftp6 service for this Nic handle
392 //
393 Status = Mtftp6CreateService (
394 Controller,
395 This->DriverBindingHandle,
396 &Service
397 );
398
399 if (EFI_ERROR (Status)) {
400 return Status;
401 }
402
403 ASSERT (Service != NULL);
404
405 //
406 // Start the internal timer to track the packet retransmission.
407 //
408 Status = gBS->SetTimer (
409 Service->Timer,
410 TimerPeriodic,
411 TICKS_PER_SECOND
412 );
413
414 if (EFI_ERROR (Status)) {
415 goto ON_ERROR;
416 }
417
418 //
419 // Install the Mtftp6 service on the Nic handle.
420 //
421 Status = gBS->InstallMultipleProtocolInterfaces (
422 &Controller,
423 &gEfiMtftp6ServiceBindingProtocolGuid,
424 &Service->ServiceBinding,
425 NULL
426 );
427
428 if (EFI_ERROR (Status)) {
429 goto ON_ERROR;
430 }
431
432 return EFI_SUCCESS;
433
434 ON_ERROR:
435
436 Mtftp6DestroyService (Service);
437 return Status;
438 }
439
440
441 /**
442 Stop this driver on Controller. This service is called by the
443 EFI boot service DisconnectController(). In order to
444 make drivers as small as possible, there are calling
445 restrictions for this service. DisconnectController()
446 must follow these calling restrictions. If any other agent wishes
447 to call Stop(), it must also follow these calling restrictions.
448
449 @param[in] This Protocol instance pointer.
450 @param[in] Controller Handle of device to stop driver on
451 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
452 children is zero, stop the entire bus driver.
453 @param[in] ChildHandleBuffer List of Child Handles to Stop.
454
455 @retval EFI_SUCCESS This driver is removed Controller.
456 @retval EFI_DEVICE_ERROR An unexpected error.
457 @retval Others This driver was not removed from this device.
458
459 **/
460 EFI_STATUS
461 EFIAPI
462 Mtftp6DriverBindingStop (
463 IN EFI_DRIVER_BINDING_PROTOCOL *This,
464 IN EFI_HANDLE Controller,
465 IN UINTN NumberOfChildren,
466 IN EFI_HANDLE *ChildHandleBuffer
467 )
468 {
469 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
470 MTFTP6_SERVICE *Service;
471 EFI_HANDLE NicHandle;
472 EFI_STATUS Status;
473 LIST_ENTRY *List;
474 MTFTP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
475
476 //
477 // Locate the Nic handle to retrieve the Mtftp6 private data.
478 //
479 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp6ProtocolGuid);
480
481 if (NicHandle == NULL) {
482 return EFI_SUCCESS;
483 }
484
485 Status = gBS->OpenProtocol (
486 NicHandle,
487 &gEfiMtftp6ServiceBindingProtocolGuid,
488 (VOID **) &ServiceBinding,
489 This->DriverBindingHandle,
490 NicHandle,
491 EFI_OPEN_PROTOCOL_GET_PROTOCOL
492 );
493
494 if (EFI_ERROR (Status)) {
495 return EFI_DEVICE_ERROR;
496 }
497
498 Service = MTFTP6_SERVICE_FROM_THIS (ServiceBinding);
499
500 if (!IsListEmpty (&Service->Children)) {
501 //
502 // Destroy the Mtftp6 child instance in ChildHandleBuffer.
503 //
504 List = &Service->Children;
505 Context.ServiceBinding = ServiceBinding;
506 Context.NumberOfChildren = NumberOfChildren;
507 Context.ChildHandleBuffer = ChildHandleBuffer;
508 Status = NetDestroyLinkList (
509 List,
510 Mtftp6DestroyChildEntryInHandleBuffer,
511 &Context,
512 NULL
513 );
514 }
515
516 if (NumberOfChildren == 0 && IsListEmpty (&Service->Children)) {
517 //
518 // Destroy the Mtftp6 service if there is no Mtftp6 child instance left.
519 //
520 gBS->UninstallProtocolInterface (
521 NicHandle,
522 &gEfiMtftp6ServiceBindingProtocolGuid,
523 ServiceBinding
524 );
525
526 Mtftp6DestroyService (Service);
527 Status = EFI_SUCCESS;
528 }
529
530 return Status;
531 }
532
533
534 /**
535 Creates a child handle and installs a protocol.
536
537 The CreateChild() function installs a protocol on ChildHandle.
538 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
539 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
540
541 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
542 @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL,
543 then a new handle is created. If it is a pointer to an existing
544 UEFI handle, then the protocol is added to the existing UEFI handle.
545
546 @retval EFI_SUCCES The protocol was added to ChildHandle.
547 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
548 @retval Others The child handle was not created.
549
550 **/
551 EFI_STATUS
552 EFIAPI
553 Mtftp6ServiceBindingCreateChild (
554 IN EFI_SERVICE_BINDING_PROTOCOL *This,
555 IN OUT EFI_HANDLE *ChildHandle
556 )
557 {
558 MTFTP6_SERVICE *Service;
559 MTFTP6_INSTANCE *Instance;
560 EFI_STATUS Status;
561 EFI_TPL OldTpl;
562 VOID *Udp6;
563
564 if (This == NULL || ChildHandle == NULL) {
565 return EFI_INVALID_PARAMETER;
566 }
567
568 Service = MTFTP6_SERVICE_FROM_THIS (This);
569
570 Status = Mtftp6CreateInstance (Service, &Instance);
571
572 if (EFI_ERROR (Status)) {
573 return Status;
574 }
575
576 ASSERT (Instance != NULL);
577
578 //
579 // Install the Mtftp6 protocol on the new child handle.
580 //
581 Status = gBS->InstallMultipleProtocolInterfaces (
582 ChildHandle,
583 &gEfiMtftp6ProtocolGuid,
584 &Instance->Mtftp6,
585 NULL
586 );
587
588 if (EFI_ERROR (Status)) {
589 goto ON_ERROR;
590 }
591
592 Instance->Handle = *ChildHandle;
593
594 //
595 // Open the Udp6 protocol by child.
596 //
597 Status = gBS->OpenProtocol (
598 Service->DummyUdpIo->UdpHandle,
599 &gEfiUdp6ProtocolGuid,
600 (VOID **) &Udp6,
601 gMtftp6DriverBinding.DriverBindingHandle,
602 Instance->Handle,
603 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
604 );
605
606 if (EFI_ERROR (Status)) {
607 gBS->UninstallMultipleProtocolInterfaces (
608 Instance->Handle,
609 &gEfiMtftp6ProtocolGuid,
610 &Instance->Mtftp6,
611 NULL
612 );
613
614 goto ON_ERROR;
615 }
616
617 //
618 // Add the new Mtftp6 instance into the children list of Mtftp6 service.
619 //
620 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
621
622 InsertTailList (&Service->Children, &Instance->Link);
623 Service->ChildrenNum++;
624
625 gBS->RestoreTPL (OldTpl);
626 return EFI_SUCCESS;
627
628 ON_ERROR:
629
630 Mtftp6DestroyInstance (Instance);
631 return Status;
632 }
633
634
635 /**
636 Destroys a child handle with a protocol installed on it.
637
638 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
639 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
640 last protocol on ChildHandle, then ChildHandle is destroyed.
641
642 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
643 @param[in] ChildHandle Handle of the child to destroy.
644
645 @retval EFI_SUCCES The protocol was removed from ChildHandle.
646 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
647 @retval EFI_INVALID_PARAMETER Child handle is NULL.
648 @retval Others The child handle was not destroyed
649
650 **/
651 EFI_STATUS
652 EFIAPI
653 Mtftp6ServiceBindingDestroyChild (
654 IN EFI_SERVICE_BINDING_PROTOCOL *This,
655 IN EFI_HANDLE ChildHandle
656 )
657 {
658 MTFTP6_SERVICE *Service;
659 MTFTP6_INSTANCE *Instance;
660 EFI_MTFTP6_PROTOCOL *Mtftp6;
661 EFI_STATUS Status;
662 EFI_TPL OldTpl;
663
664 if (This == NULL || ChildHandle == NULL) {
665 return EFI_INVALID_PARAMETER;
666 }
667
668 //
669 // Locate the Nic handle to retrieve the Mtftp6 private data.
670 //
671 Status = gBS->OpenProtocol (
672 ChildHandle,
673 &gEfiMtftp6ProtocolGuid,
674 (VOID **) &Mtftp6,
675 gMtftp6DriverBinding.DriverBindingHandle,
676 ChildHandle,
677 EFI_OPEN_PROTOCOL_GET_PROTOCOL
678 );
679
680 if (EFI_ERROR (Status)) {
681 return EFI_UNSUPPORTED;
682 }
683
684 Instance = MTFTP6_INSTANCE_FROM_THIS (Mtftp6);
685 Service = MTFTP6_SERVICE_FROM_THIS (This);
686
687 if (Instance->Service != Service) {
688 return EFI_INVALID_PARAMETER;
689 }
690
691 //
692 // Check whether the instance already in Destroy state.
693 //
694 if (Instance->InDestroy) {
695 return EFI_SUCCESS;
696 }
697
698 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
699
700 Instance->InDestroy = TRUE;
701
702 gBS->CloseProtocol (
703 Service->DummyUdpIo->UdpHandle,
704 &gEfiUdp6ProtocolGuid,
705 gMtftp6DriverBinding.DriverBindingHandle,
706 ChildHandle
707 );
708
709 if (Instance->UdpIo != NULL) {
710 gBS->CloseProtocol (
711 Instance->UdpIo->UdpHandle,
712 &gEfiUdp6ProtocolGuid,
713 gMtftp6DriverBinding.DriverBindingHandle,
714 Instance->Handle
715 );
716 }
717
718 if (Instance->McastUdpIo != NULL) {
719 gBS->CloseProtocol (
720 Instance->McastUdpIo->UdpHandle,
721 &gEfiUdp6ProtocolGuid,
722 gMtftp6DriverBinding.DriverBindingHandle,
723 Instance->Handle
724 );
725 }
726
727 //
728 // Uninstall the MTFTP6 protocol first to enable a top down destruction.
729 //
730 gBS->RestoreTPL (OldTpl);
731 Status = gBS->UninstallProtocolInterface (
732 ChildHandle,
733 &gEfiMtftp6ProtocolGuid,
734 Mtftp6
735 );
736 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
737 if (EFI_ERROR (Status)) {
738 Instance->InDestroy = FALSE;
739 gBS->RestoreTPL (OldTpl);
740 return Status;
741 }
742
743 //
744 // Remove the Mtftp6 instance from the children list of Mtftp6 service.
745 //
746 RemoveEntryList (&Instance->Link);
747 Service->ChildrenNum --;
748
749 gBS->RestoreTPL (OldTpl);
750
751 Mtftp6DestroyInstance (Instance);
752
753 return EFI_SUCCESS;
754 }