]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Mtftp6Dxe/Mtftp6Driver.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / Mtftp6Dxe / Mtftp6Driver.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Driver Binding functions and Service Binding functions\r
3 implementation for Mtftp6 Driver.\r
4\r
f75a7f56 5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 6\r
ecf98fbc 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
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
75dce340 30 Destroy the MTFTP6 service. The MTFTP6 service may be partly initialized,\r
a3bcde70
HT
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
75dce340 43 // Make sure all children instances have been already destroyed.\r
a3bcde70
HT
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
a3bcde70
HT
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
75dce340 215 Mtftp6Ins->InDestroy = FALSE;\r
a3bcde70
HT
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
216f7970 233/**\r
234 Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
f75a7f56 235\r
216f7970 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
1f7eb561 244EFIAPI\r
216f7970 245Mtftp6DestroyChildEntryInHandleBuffer (\r
246 IN LIST_ENTRY *Entry,\r
247 IN VOID *Context\r
1f7eb561 248 )\r
216f7970 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
a3bcde70
HT
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
76389e18 305 Test to see if this driver supports Controller. This service\r
a3bcde70
HT
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
76389e18 313 @param[in] Controller Handle of device to test\r
a3bcde70
HT
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
76389e18 341 Start this driver on Controller. This service is called by the\r
a3bcde70
HT
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
76389e18 349 @param[in] Controller Handle of device to bind driver to.\r
a3bcde70
HT
350 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
351 device to start.\r
352\r
76389e18 353 @retval EFI_SUCCESS This driver is added to Controller.\r
354 @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
a3bcde70
HT
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
76389e18 437 Stop this driver on Controller. This service is called by the\r
a3bcde70 438 EFI boot service DisconnectController(). In order to\r
76389e18 439 make drivers as small as possible, there are calling\r
a3bcde70
HT
440 restrictions for this service. DisconnectController()\r
441 must follow these calling restrictions. If any other agent wishes\r
76389e18 442 to call Stop(), it must also follow these calling restrictions.\r
a3bcde70
HT
443\r
444 @param[in] This Protocol instance pointer.\r
76389e18 445 @param[in] Controller Handle of device to stop driver on\r
a3bcde70
HT
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
76389e18 450 @retval EFI_SUCCESS This driver is removed Controller.\r
a3bcde70
HT
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
216f7970 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
f75a7f56 470\r
a3bcde70
HT
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
216f7970 477 return EFI_SUCCESS;\r
a3bcde70
HT
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
216f7970 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
a3bcde70
HT
509 }\r
510\r
216f7970 511 if (NumberOfChildren == 0 && IsListEmpty (&Service->Children)) {\r
a3bcde70 512 //\r
75dce340 513 // Destroy the Mtftp6 service if there is no Mtftp6 child instance left.\r
a3bcde70 514 //\r
a3bcde70
HT
515 gBS->UninstallProtocolInterface (\r
516 NicHandle,\r
517 &gEfiMtftp6ServiceBindingProtocolGuid,\r
518 ServiceBinding\r
519 );\r
520\r
521 Mtftp6DestroyService (Service);\r
216f7970 522 Status = EFI_SUCCESS;\r
a3bcde70
HT
523 }\r
524\r
a3bcde70
HT
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
15ee13fc 642 @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
a3bcde70
HT
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
75dce340 687 // Check whether the instance already in Destroy state.\r
a3bcde70 688 //\r
75dce340 689 if (Instance->InDestroy) {\r
a3bcde70
HT
690 return EFI_SUCCESS;\r
691 }\r
692\r
693 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
694\r
75dce340 695 Instance->InDestroy = TRUE;\r
a3bcde70
HT
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
216f7970 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
a3bcde70
HT
722 //\r
723 // Uninstall the MTFTP6 protocol first to enable a top down destruction.\r
724 //\r
216f7970 725 gBS->RestoreTPL (OldTpl);\r
a3bcde70
HT
726 Status = gBS->UninstallProtocolInterface (\r
727 ChildHandle,\r
728 &gEfiMtftp6ProtocolGuid,\r
729 Mtftp6\r
730 );\r
216f7970 731 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
a3bcde70 732 if (EFI_ERROR (Status)) {\r
75dce340 733 Instance->InDestroy = FALSE;\r
a3bcde70
HT
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
a3bcde70
HT
744 gBS->RestoreTPL (OldTpl);\r
745\r
216f7970 746 Mtftp6DestroyInstance (Instance);\r
747\r
a3bcde70
HT
748 return EFI_SUCCESS;\r
749}\r