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