]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c
Update for NetworkPkg.
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Driver.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Driver Binding functions and Service Binding functions\r
3 implementationfor for Dhcp6 Driver.\r
4\r
15ee13fc 5 Copyright (c) 2009 - 2011, 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 "Dhcp6Impl.h"\r
18\r
19\r
20EFI_DRIVER_BINDING_PROTOCOL gDhcp6DriverBinding = {\r
21 Dhcp6DriverBindingSupported,\r
22 Dhcp6DriverBindingStart,\r
23 Dhcp6DriverBindingStop,\r
24 0xa,\r
25 NULL,\r
26 NULL\r
27};\r
28\r
29EFI_SERVICE_BINDING_PROTOCOL gDhcp6ServiceBindingTemplate = {\r
30 Dhcp6ServiceBindingCreateChild,\r
31 Dhcp6ServiceBindingDestroyChild\r
32};\r
33\r
34\r
35/**\r
36 Configure the default Udp6Io to receive all the DHCP6 traffic\r
37 on this network interface.\r
38\r
39 @param[in] UdpIo The pointer to Udp6Io to be configured.\r
40 @param[in] Context The pointer to the context.\r
41\r
42 @retval EFI_SUCCESS The Udp6Io is successfully configured.\r
43 @retval Others Failed to configure the Udp6Io.\r
44\r
45**/\r
46EFI_STATUS\r
47EFIAPI\r
48Dhcp6ConfigureUdpIo (\r
49 IN UDP_IO *UdpIo,\r
50 IN VOID *Context\r
51 )\r
52{\r
53 EFI_UDP6_PROTOCOL *Udp6;\r
54 EFI_UDP6_CONFIG_DATA *Config;\r
55\r
56 Udp6 = UdpIo->Protocol.Udp6;\r
57 Config = &(UdpIo->Config.Udp6);\r
58\r
59 ZeroMem (Config, sizeof (EFI_UDP6_CONFIG_DATA));\r
60\r
61 //\r
62 // Set Udp6 configure data for the Dhcp6 instance.\r
63 //\r
64 Config->AcceptPromiscuous = FALSE;\r
65 Config->AcceptAnyPort = FALSE;\r
66 Config->AllowDuplicatePort = FALSE;\r
67 Config->TrafficClass = 0;\r
68 Config->HopLimit = 128;\r
69 Config->ReceiveTimeout = 0;\r
70 Config->TransmitTimeout = 0;\r
71\r
72 //\r
73 // Configure an endpoint of client(0, 546), server(0, 0), the addresses\r
74 // will be overridden later. Note that we MUST not limit RemotePort.\r
75 // More details, refer to RFC 3315 section 5.2.\r
76 //\r
77 Config->StationPort = DHCP6_PORT_CLIENT;\r
78 Config->RemotePort = 0;\r
79\r
80 return Udp6->Configure (Udp6, Config);;\r
81}\r
82\r
83\r
84/**\r
85 Destory the Dhcp6 service. The Dhcp6 service may be partly initialized,\r
86 or partly destroyed. If a resource is destroyed, it is marked as such in\r
87 case the destroy failed and being called again later.\r
88\r
89 @param[in, out] Service The pointer to Dhcp6 service to be destroyed.\r
90\r
91**/\r
92VOID\r
93Dhcp6DestroyService (\r
94 IN OUT DHCP6_SERVICE *Service\r
95 )\r
96{\r
97 //\r
98 // All children instances should have been already destoryed here.\r
99 //\r
100 ASSERT (Service->NumOfChild == 0);\r
101\r
102 if (Service->ClientId != NULL) {\r
103 FreePool (Service->ClientId);\r
104 }\r
105\r
106 if (Service->UdpIo != NULL) {\r
107 UdpIoFreeIo (Service->UdpIo);\r
108 }\r
109\r
110 FreePool (Service);\r
111}\r
112\r
113\r
114/**\r
115 Create a new Dhcp6 service for the Nic controller.\r
116\r
117 @param[in] Controller The controller to be installed DHCP6 service\r
118 binding protocol.\r
119 @param[in] ImageHandle The image handle of the Dhcp6 driver.\r
120 @param[out] Service The return pointer of the new Dhcp6 service.\r
121\r
122 @retval EFI_SUCCESS The Dhcp6 service is created successfully.\r
123 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
124 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
125\r
126**/\r
127EFI_STATUS\r
128Dhcp6CreateService (\r
129 IN EFI_HANDLE Controller,\r
130 IN EFI_HANDLE ImageHandle,\r
131 OUT DHCP6_SERVICE **Service\r
132 )\r
133{\r
134 DHCP6_SERVICE *Dhcp6Srv;\r
135\r
136 *Service = NULL;\r
137 Dhcp6Srv = AllocateZeroPool (sizeof (DHCP6_SERVICE));\r
138\r
139 if (Dhcp6Srv == NULL) {\r
140 return EFI_OUT_OF_RESOURCES;\r
141 }\r
142\r
143 //\r
144 // Open the SNP protocol to get mode data later.\r
145 //\r
146 Dhcp6Srv->Snp = NULL;\r
147 NetLibGetSnpHandle (Controller, &Dhcp6Srv->Snp);\r
148 if (Dhcp6Srv->Snp == NULL) {\r
149 FreePool (Dhcp6Srv);\r
150 return EFI_DEVICE_ERROR;\r
151 }\r
152\r
153 //\r
154 // Initialize the fields of the new Dhcp6 service.\r
155 //\r
156 Dhcp6Srv->Signature = DHCP6_SERVICE_SIGNATURE;\r
157 Dhcp6Srv->InDestory = FALSE;\r
158 Dhcp6Srv->Controller = Controller;\r
159 Dhcp6Srv->Image = ImageHandle;\r
160 Dhcp6Srv->Xid = (0xffffff & NET_RANDOM (NetRandomInitSeed ()));\r
161\r
162 CopyMem (\r
163 &Dhcp6Srv->ServiceBinding,\r
164 &gDhcp6ServiceBindingTemplate,\r
165 sizeof (EFI_SERVICE_BINDING_PROTOCOL)\r
166 );\r
167\r
168 //\r
33c09637 169 // Generate client Duid: If SMBIOS system UUID is located, generate DUID in DUID-UUID format.\r
170 // Otherwise, in DUID-LLT format.\r
a3bcde70
HT
171 //\r
172 Dhcp6Srv->ClientId = Dhcp6GenerateClientId (Dhcp6Srv->Snp->Mode);\r
173\r
174 if (Dhcp6Srv->ClientId == NULL) {\r
175 FreePool (Dhcp6Srv);\r
176 return EFI_DEVICE_ERROR;\r
177 }\r
178\r
179 //\r
180 // Create an Udp6Io for stateful transmit/receive of each Dhcp6 instance.\r
181 //\r
182 Dhcp6Srv->UdpIo = UdpIoCreateIo (\r
183 Controller,\r
184 ImageHandle,\r
185 Dhcp6ConfigureUdpIo,\r
186 UDP_IO_UDP6_VERSION,\r
187 NULL\r
188 );\r
189\r
190 if (Dhcp6Srv->UdpIo == NULL) {\r
191 FreePool (Dhcp6Srv->ClientId);\r
192 FreePool (Dhcp6Srv);\r
193 return EFI_DEVICE_ERROR;\r
194 }\r
195\r
196 InitializeListHead (&Dhcp6Srv->Child);\r
197\r
198 *Service = Dhcp6Srv;\r
199\r
200 return EFI_SUCCESS;\r
201}\r
202\r
203\r
204/**\r
205 Destroy the Dhcp6 instance and recycle the resources.\r
206\r
207 @param[in, out] Instance The pointer to the Dhcp6 instance.\r
208\r
209**/\r
210VOID\r
211Dhcp6DestroyInstance (\r
212 IN OUT DHCP6_INSTANCE *Instance\r
213 )\r
214{\r
215 //\r
216 // Clean up the retry list first.\r
217 //\r
218 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);\r
219 gBS->CloseEvent (Instance->Timer);\r
220\r
221 //\r
222 // Clean up the current configure data.\r
223 //\r
224 if (Instance->Config != NULL) {\r
225 Dhcp6CleanupConfigData (Instance->Config);\r
226 FreePool (Instance->Config);\r
227 }\r
228\r
229 //\r
230 // Clean up the current Ia.\r
231 //\r
232 if (Instance->IaCb.Ia != NULL) {\r
233 if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
234 FreePool (Instance->IaCb.Ia->ReplyPacket);\r
235 }\r
236 FreePool (Instance->IaCb.Ia);\r
237 }\r
238\r
239 if (Instance->Unicast != NULL) {\r
240 FreePool (Instance->Unicast);\r
241 }\r
242\r
243 if (Instance->AdSelect != NULL) {\r
244 FreePool (Instance->AdSelect);\r
245 }\r
246\r
247 FreePool (Instance);\r
248}\r
249\r
250\r
251/**\r
252 Create the Dhcp6 instance and initialize it.\r
253\r
254 @param[in] Service The pointer to the Dhcp6 service.\r
255 @param[out] Instance The pointer to the Dhcp6 instance.\r
256\r
257 @retval EFI_SUCCESS The Dhcp6 instance is created.\r
258 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
259\r
260**/\r
261EFI_STATUS\r
262Dhcp6CreateInstance (\r
263 IN DHCP6_SERVICE *Service,\r
264 OUT DHCP6_INSTANCE **Instance\r
265 )\r
266{\r
267 EFI_STATUS Status;\r
268 DHCP6_INSTANCE *Dhcp6Ins;\r
269\r
270 *Instance = NULL;\r
271 Dhcp6Ins = AllocateZeroPool (sizeof (DHCP6_INSTANCE));\r
272\r
273 if (Dhcp6Ins == NULL) {\r
274 return EFI_OUT_OF_RESOURCES;\r
275 }\r
276\r
277 //\r
278 // Initialize the fields of the new Dhcp6 instance.\r
279 //\r
280 Dhcp6Ins->Signature = DHCP6_INSTANCE_SIGNATURE;\r
281 Dhcp6Ins->UdpSts = EFI_ALREADY_STARTED;\r
282 Dhcp6Ins->Service = Service;\r
283 Dhcp6Ins->InDestory = FALSE;\r
284 Dhcp6Ins->MediaPresent = TRUE;\r
285\r
286 CopyMem (\r
287 &Dhcp6Ins->Dhcp6,\r
288 &gDhcp6ProtocolTemplate,\r
289 sizeof (EFI_DHCP6_PROTOCOL)\r
290 );\r
291\r
292 InitializeListHead (&Dhcp6Ins->TxList);\r
293 InitializeListHead (&Dhcp6Ins->InfList);\r
294\r
295 //\r
296 // There is a timer for each Dhcp6 instance, which is used to track the\r
297 // lease time of Ia and the retransmisson time of all sent packets.\r
298 //\r
299 Status = gBS->CreateEvent (\r
300 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
301 TPL_CALLBACK,\r
302 Dhcp6OnTimerTick,\r
303 Dhcp6Ins,\r
304 &Dhcp6Ins->Timer\r
305 );\r
306\r
307 if (EFI_ERROR (Status)) {\r
308 FreePool (Dhcp6Ins);\r
309 return Status;\r
310 }\r
311\r
312 *Instance = Dhcp6Ins;\r
313\r
314 return EFI_SUCCESS;\r
315}\r
316\r
317\r
318/**\r
319 Entry point of the DHCP6 driver to install various protocols.\r
320\r
321 @param[in] ImageHandle The handle of the UEFI image file.\r
322 @param[in] SystemTable The pointer to the EFI System Table.\r
323\r
324 @retval EFI_SUCCESS The operation completed successfully.\r
325 @retval Others Unexpected error occurs.\r
326\r
327**/\r
328EFI_STATUS\r
329EFIAPI\r
330Dhcp6DriverEntryPoint (\r
331 IN EFI_HANDLE ImageHandle,\r
332 IN EFI_SYSTEM_TABLE *SystemTable\r
333 )\r
334{\r
335 return EfiLibInstallDriverBindingComponentName2 (\r
336 ImageHandle,\r
337 SystemTable,\r
338 &gDhcp6DriverBinding,\r
339 ImageHandle,\r
340 &gDhcp6ComponentName,\r
341 &gDhcp6ComponentName2\r
342 );\r
343}\r
344\r
345\r
346/**\r
347 Test to see if this driver supports ControllerHandle. This service\r
348 is called by the EFI boot service ConnectController(). In\r
349 order to make drivers as small as possible, there are a few calling\r
350 restrictions for this service. ConnectController() must\r
351 follow these calling restrictions. If any other agent wishes to call\r
352 Supported() it must also follow these calling restrictions.\r
353\r
354 @param[in] This The pointer to the driver binding protocol.\r
355 @param[in] ControllerHandle The handle of device to be tested.\r
356 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
357 device to be started.\r
358\r
359 @retval EFI_SUCCESS This driver supports this device.\r
360 @retval Others This driver does not support this device.\r
361\r
362**/\r
363EFI_STATUS\r
364EFIAPI\r
365Dhcp6DriverBindingSupported (\r
366 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
367 IN EFI_HANDLE ControllerHandle,\r
368 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
369 )\r
370{\r
371 return gBS->OpenProtocol (\r
372 ControllerHandle,\r
373 &gEfiUdp6ServiceBindingProtocolGuid,\r
374 NULL,\r
375 This->DriverBindingHandle,\r
376 ControllerHandle,\r
377 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
378 );\r
379}\r
380\r
381\r
382/**\r
383 Start this driver on ControllerHandle. This service is called by the\r
384 EFI boot service ConnectController(). In order to make\r
385 drivers as small as possible, there are a few calling restrictions for\r
386 this service. ConnectController() must follow these\r
387 calling restrictions. If any other agent wishes to call Start() it\r
388 must also follow these calling restrictions.\r
389\r
390 @param[in] This The pointer to the driver binding protocol.\r
391 @param[in] ControllerHandle The handle of device to be started.\r
392 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
393 device to be started.\r
394\r
395 @retval EFI_SUCCESS This driver is installed to ControllerHandle.\r
396 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.\r
397 @retval other This driver does not support this device.\r
398\r
399**/\r
400EFI_STATUS\r
401EFIAPI\r
402Dhcp6DriverBindingStart (\r
403 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
404 IN EFI_HANDLE ControllerHandle,\r
405 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
406 )\r
407{\r
408 EFI_STATUS Status;\r
409 DHCP6_SERVICE *Service;\r
410\r
411 //\r
412 // Check the Dhcp6 serivce whether already started.\r
413 //\r
414 Status = gBS->OpenProtocol (\r
415 ControllerHandle,\r
416 &gEfiDhcp6ServiceBindingProtocolGuid,\r
417 NULL,\r
418 This->DriverBindingHandle,\r
419 ControllerHandle,\r
420 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
421 );\r
422\r
423 if (!EFI_ERROR (Status)) {\r
424 return EFI_ALREADY_STARTED;\r
425 }\r
426\r
427 //\r
428 // Create and initialize the Dhcp6 service.\r
429 //\r
430 Status = Dhcp6CreateService (\r
431 ControllerHandle,\r
432 This->DriverBindingHandle,\r
433 &Service\r
434 );\r
435\r
436 if (EFI_ERROR (Status)) {\r
437 return Status;\r
438 }\r
439\r
440 ASSERT (Service != NULL);\r
441\r
442 Status = gBS->InstallMultipleProtocolInterfaces (\r
443 &ControllerHandle,\r
444 &gEfiDhcp6ServiceBindingProtocolGuid,\r
445 &Service->ServiceBinding,\r
446 NULL\r
447 );\r
448\r
449 if (EFI_ERROR (Status)) {\r
450 Dhcp6DestroyService (Service);\r
451 return Status;\r
452 }\r
453\r
454 return EFI_SUCCESS;\r
455}\r
456\r
457\r
458/**\r
459 Stop this driver on ControllerHandle. This service is called by the\r
460 EFI boot service DisconnectController(). In order to\r
461 make drivers as small as possible, there are a few calling\r
462 restrictions for this service. DisconnectController()\r
463 must follow these calling restrictions. If any other agent wishes\r
464 to call Stop() it must also follow these calling restrictions.\r
465\r
466 @param[in] This Protocol instance pointer.\r
467 @param[in] ControllerHandle Handle of device to stop driver on\r
468 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
469 children is zero stop the entire bus driver.\r
470 @param[in] ChildHandleBuffer List of Child Handles to Stop.\r
471\r
472 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
473 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
474 @retval other This driver was not removed from this device\r
475\r
476**/\r
477EFI_STATUS\r
478EFIAPI\r
479Dhcp6DriverBindingStop (\r
480 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
481 IN EFI_HANDLE ControllerHandle,\r
482 IN UINTN NumberOfChildren,\r
483 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
484 )\r
485{\r
486 EFI_STATUS Status;\r
487 EFI_TPL OldTpl;\r
488 EFI_HANDLE NicHandle;\r
489 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
490 DHCP6_SERVICE *Service;\r
491 DHCP6_INSTANCE *Instance;\r
492\r
493 //\r
494 // Find and check the Nic handle by the controller handle.\r
495 //\r
496 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);\r
497\r
498 if (NicHandle == NULL) {\r
499 return EFI_DEVICE_ERROR;\r
500 }\r
501\r
502 Status = gBS->OpenProtocol (\r
503 NicHandle,\r
504 &gEfiDhcp6ServiceBindingProtocolGuid,\r
505 (VOID **) &ServiceBinding,\r
506 This->DriverBindingHandle,\r
507 NicHandle,\r
508 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
509 );\r
510\r
511 if (EFI_ERROR (Status)) {\r
512 return Status;\r
513 }\r
514\r
515 Service = DHCP6_SERVICE_FROM_THIS (ServiceBinding);\r
516\r
517 if (Service->InDestory) {\r
518 return EFI_SUCCESS;\r
519 }\r
520\r
521 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
522\r
523 if (NumberOfChildren == 0) {\r
524 //\r
525 // Destory the service itself if no child instance left.\r
526 //\r
527 Service->InDestory = TRUE;\r
528\r
529 Status = gBS->UninstallProtocolInterface (\r
530 NicHandle,\r
531 &gEfiDhcp6ServiceBindingProtocolGuid,\r
532 ServiceBinding\r
533 );\r
534\r
535 if (EFI_ERROR (Status)) {\r
536 Service->InDestory = FALSE;\r
537 goto ON_EXIT;\r
538 }\r
539\r
540 Dhcp6DestroyService (Service);\r
541\r
542 } else {\r
543 //\r
544 // Destory all the children instances before destory the service.\r
545 //\r
546 while (!IsListEmpty (&Service->Child)) {\r
547 Instance = NET_LIST_HEAD (&Service->Child, DHCP6_INSTANCE, Link);\r
548 ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
549 }\r
550 //\r
551 // Any of child failed to be destroyed.\r
552 //\r
553 if (Service->NumOfChild != 0) {\r
554 Status = EFI_DEVICE_ERROR;\r
555 }\r
556 }\r
557\r
558ON_EXIT:\r
559 gBS->RestoreTPL (OldTpl);\r
560 return Status;\r
561}\r
562\r
563\r
564/**\r
565 Creates a child handle and installs a protocol.\r
566\r
567 The CreateChild() function installs a protocol on ChildHandle.\r
568 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
569 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
570\r
571 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
572 @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
573 then a new handle is created. If it is a pointer to an existing\r
574 UEFI handle, then the protocol is added to the existing UEFI handle.\r
575\r
576 @retval EFI_SUCCES The protocol was added to ChildHandle.\r
577 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
578 @retval other The child handle was not created.\r
579\r
580**/\r
581EFI_STATUS\r
582EFIAPI\r
583Dhcp6ServiceBindingCreateChild (\r
584 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
585 IN OUT EFI_HANDLE *ChildHandle\r
586 )\r
587{\r
588 EFI_STATUS Status;\r
589 EFI_TPL OldTpl;\r
590 DHCP6_SERVICE *Service;\r
591 DHCP6_INSTANCE *Instance;\r
592 VOID *Udp6;\r
593\r
594 if (This == NULL || ChildHandle == NULL) {\r
595 return EFI_INVALID_PARAMETER;\r
596 }\r
597\r
598 Service = DHCP6_SERVICE_FROM_THIS (This);\r
599\r
600 Status = Dhcp6CreateInstance (Service, &Instance);\r
601\r
602 if (EFI_ERROR (Status)) {\r
603 return Status;\r
604 }\r
605\r
606 ASSERT (Instance != NULL);\r
607\r
608 //\r
609 // Start the timer when the instance is ready to use.\r
610 //\r
611 Status = gBS->SetTimer (\r
612 Instance->Timer,\r
613 TimerPeriodic,\r
614 TICKS_PER_SECOND\r
615 );\r
616\r
617 if (EFI_ERROR (Status)) {\r
618 goto ON_ERROR;\r
619 }\r
620\r
621 //\r
622 // Install the DHCP6 protocol onto ChildHandle.\r
623 //\r
624 Status = gBS->InstallMultipleProtocolInterfaces (\r
625 ChildHandle,\r
626 &gEfiDhcp6ProtocolGuid,\r
627 &Instance->Dhcp6,\r
628 NULL\r
629 );\r
630\r
631 if (EFI_ERROR (Status)) {\r
632 goto ON_ERROR;\r
633 }\r
634\r
635 Instance->Handle = *ChildHandle;\r
636\r
637 //\r
638 // Open the UDP6 protocol BY_CHILD.\r
639 //\r
640 Status = gBS->OpenProtocol (\r
641 Service->UdpIo->UdpHandle,\r
642 &gEfiUdp6ProtocolGuid,\r
643 (VOID **) &Udp6,\r
644 gDhcp6DriverBinding.DriverBindingHandle,\r
645 Instance->Handle,\r
646 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
647 );\r
648\r
649 if (EFI_ERROR (Status)) {\r
650\r
651 gBS->UninstallMultipleProtocolInterfaces (\r
652 Instance->Handle,\r
653 &gEfiDhcp6ProtocolGuid,\r
654 &Instance->Dhcp6,\r
655 NULL\r
656 );\r
657 goto ON_ERROR;\r
658 }\r
659\r
660 //\r
661 // Add into the children list of its parent service.\r
662 //\r
663 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
664\r
665 InsertTailList (&Service->Child, &Instance->Link);\r
666 Service->NumOfChild++;\r
667\r
668 gBS->RestoreTPL (OldTpl);\r
669 return EFI_SUCCESS;\r
670\r
671ON_ERROR:\r
672\r
673 Dhcp6DestroyInstance (Instance);\r
674 return Status;\r
675}\r
676\r
677\r
678/**\r
679 Destroys a child handle with a protocol installed on it.\r
680\r
681 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
682 that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
683 last protocol on ChildHandle, then ChildHandle is destroyed.\r
684\r
685 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
686 @param[in] ChildHandle Handle of the child to destroy\r
687\r
688 @retval EFI_SUCCES The protocol was removed from ChildHandle.\r
689 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
15ee13fc 690 @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
a3bcde70
HT
691 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
692 because its services are being used.\r
693 @retval other The child handle was not destroyed\r
694\r
695**/\r
696EFI_STATUS\r
697EFIAPI\r
698Dhcp6ServiceBindingDestroyChild (\r
699 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
700 IN EFI_HANDLE ChildHandle\r
701 )\r
702{\r
703 EFI_STATUS Status;\r
704 EFI_TPL OldTpl;\r
705 EFI_DHCP6_PROTOCOL *Dhcp6;\r
706 DHCP6_SERVICE *Service;\r
707 DHCP6_INSTANCE *Instance;\r
708\r
709 if (This == NULL || ChildHandle == NULL) {\r
710 return EFI_INVALID_PARAMETER;\r
711 }\r
712\r
713 //\r
714 // Retrieve the private context data structures\r
715 //\r
716 Status = gBS->OpenProtocol (\r
717 ChildHandle,\r
718 &gEfiDhcp6ProtocolGuid,\r
719 (VOID **) &Dhcp6,\r
720 gDhcp6DriverBinding.DriverBindingHandle,\r
721 ChildHandle,\r
722 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
723 );\r
724\r
725 if (EFI_ERROR (Status)) {\r
726 return EFI_UNSUPPORTED;\r
727 }\r
728\r
729 Instance = DHCP6_INSTANCE_FROM_THIS (Dhcp6);\r
730 Service = DHCP6_SERVICE_FROM_THIS (This);\r
731\r
732 if (Instance->Service != Service) {\r
733 return EFI_INVALID_PARAMETER;\r
734 }\r
735\r
736 if (Instance->InDestory) {\r
737 return EFI_SUCCESS;\r
738 }\r
739\r
740 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
741\r
742 Instance->InDestory = TRUE;\r
743\r
744 Status = gBS->CloseProtocol (\r
745 Service->UdpIo->UdpHandle,\r
746 &gEfiUdp6ProtocolGuid,\r
747 gDhcp6DriverBinding.DriverBindingHandle,\r
748 ChildHandle\r
749 );\r
750\r
751 if (EFI_ERROR (Status)) {\r
752 Instance->InDestory = FALSE;\r
753 gBS->RestoreTPL (OldTpl);\r
754 return Status;\r
755 }\r
756\r
757 //\r
758 // Uninstall the MTFTP6 protocol first to enable a top down destruction.\r
759 //\r
760 Status = gBS->UninstallProtocolInterface (\r
761 ChildHandle,\r
762 &gEfiDhcp6ProtocolGuid,\r
763 Dhcp6\r
764 );\r
765\r
766 if (EFI_ERROR (Status)) {\r
767 Instance->InDestory = FALSE;\r
768 gBS->RestoreTPL (OldTpl);\r
769 return Status;\r
770 }\r
771\r
772 //\r
773 // Remove it from the children list of its parent service.\r
774 //\r
775 RemoveEntryList (&Instance->Link);\r
776 Service->NumOfChild--;\r
777\r
778 Dhcp6DestroyInstance (Instance);\r
779\r
780 gBS->RestoreTPL (OldTpl);\r
781\r
782 return EFI_SUCCESS;\r
783}\r