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