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