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