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