]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/DnsDxe/DnsDriver.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / DnsDxe / DnsDriver.c
1 /** @file
2 The driver binding and service binding protocol for DnsDxe driver.
3
4 Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "DnsImpl.h"
10
11 EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding = {
12 Dns4DriverBindingSupported,
13 Dns4DriverBindingStart,
14 Dns4DriverBindingStop,
15 DNS_VERSION,
16 NULL,
17 NULL
18 };
19
20 EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding = {
21 Dns6DriverBindingSupported,
22 Dns6DriverBindingStart,
23 Dns6DriverBindingStop,
24 DNS_VERSION,
25 NULL,
26 NULL
27 };
28
29 EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding = {
30 Dns4ServiceBindingCreateChild,
31 Dns4ServiceBindingDestroyChild
32 };
33
34 EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding = {
35 Dns6ServiceBindingCreateChild,
36 Dns6ServiceBindingDestroyChild
37 };
38
39 DNS_DRIVER_DATA *mDriverData = NULL;
40
41 /**
42 Destroy the DNS instance and recycle the resources.
43
44 @param[in] Instance The pointer to the DNS instance.
45
46 **/
47 VOID
48 DnsDestroyInstance (
49 IN DNS_INSTANCE *Instance
50 )
51 {
52 ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA));
53
54 ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA));
55
56 if (!NetMapIsEmpty (&Instance->Dns4TxTokens)) {
57 Dns4InstanceCancelToken (Instance, NULL);
58 }
59
60 if (!NetMapIsEmpty (&Instance->Dns6TxTokens)) {
61 Dns6InstanceCancelToken (Instance, NULL);
62 }
63
64 if (Instance->UdpIo!= NULL) {
65 UdpIoFreeIo (Instance->UdpIo);
66 }
67
68 FreePool (Instance);
69 }
70
71 /**
72 Create the DNS instance and initialize it.
73
74 @param[in] Service The pointer to the DNS service.
75 @param[out] Instance The pointer to the DNS instance.
76
77 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
78 @retval EFI_SUCCESS The DNS instance is created.
79
80 **/
81 EFI_STATUS
82 DnsCreateInstance (
83 IN DNS_SERVICE *Service,
84 OUT DNS_INSTANCE **Instance
85 )
86 {
87 DNS_INSTANCE *DnsIns;
88
89 *Instance = NULL;
90
91 DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE));
92 if (DnsIns == NULL) {
93 return EFI_OUT_OF_RESOURCES;
94 }
95
96 DnsIns->Signature = DNS_INSTANCE_SIGNATURE;
97 InitializeListHead (&DnsIns->Link);
98 DnsIns->State = DNS_STATE_UNCONFIGED;
99 DnsIns->InDestroy = FALSE;
100 DnsIns->Service = Service;
101
102 if (Service->IpVersion == IP_VERSION_4) {
103 CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4));
104 NetMapInit (&DnsIns->Dns4TxTokens);
105 } else {
106 CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6));
107 NetMapInit (&DnsIns->Dns6TxTokens);
108 }
109
110 DnsIns->UdpIo = UdpIoCreateIo (
111 Service->ControllerHandle, /// NicHandle
112 Service->ImageHandle,
113 DnsConfigNullUdp,
114 Service->IpVersion,
115 DnsIns
116 );
117 if (DnsIns->UdpIo == NULL) {
118 FreePool (DnsIns);
119 return EFI_OUT_OF_RESOURCES;
120 }
121
122 *Instance = DnsIns;
123
124 return EFI_SUCCESS;
125 }
126
127 /**
128 Callback function which provided by user to remove one node in NetDestroyLinkList process.
129
130 @param[in] Entry The entry to be removed.
131 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
132
133 @retval EFI_SUCCESS The entry has been removed successfully.
134 @retval Others Fail to remove the entry.
135
136 **/
137 EFI_STATUS
138 EFIAPI
139 DnsDestroyChildEntryInHandleBuffer (
140 IN LIST_ENTRY *Entry,
141 IN VOID *Context
142 )
143 {
144 DNS_INSTANCE *Instance;
145 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
146 UINTN NumberOfChildren;
147 EFI_HANDLE *ChildHandleBuffer;
148
149 if (Entry == NULL || Context == NULL) {
150 return EFI_INVALID_PARAMETER;
151 }
152
153 Instance = NET_LIST_USER_STRUCT_S (Entry, DNS_INSTANCE, Link, DNS_INSTANCE_SIGNATURE);
154 ServiceBinding = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
155 NumberOfChildren = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
156 ChildHandleBuffer = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
157
158 if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) {
159 return EFI_SUCCESS;
160 }
161
162 return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
163 }
164
165 /**
166 Config a NULL UDP that is used to keep the connection between UDP and DNS.
167
168 Just leave the Udp child unconfigured. When UDP is unloaded,
169 DNS will be informed with DriverBinding Stop.
170
171 @param UdpIo The UDP_IO to configure
172 @param Context The opaque parameter to the callback
173
174 @retval EFI_SUCCESS It always return EFI_SUCCESS directly.
175
176 **/
177 EFI_STATUS
178 EFIAPI
179 DnsConfigNullUdp (
180 IN UDP_IO *UdpIo,
181 IN VOID *Context
182 )
183 {
184 return EFI_SUCCESS;
185 }
186
187 /**
188 Release all the resource used the DNS service binding instance.
189
190 @param DnsSb The Dns service binding instance.
191
192 **/
193 VOID
194 DnsDestroyService (
195 IN DNS_SERVICE *DnsSb
196 )
197 {
198 UdpIoFreeIo (DnsSb->ConnectUdp);
199
200 if (DnsSb->TimerToGetMap != NULL){
201 gBS->CloseEvent (DnsSb->TimerToGetMap);
202 }
203
204 if (DnsSb->Timer != NULL){
205 gBS->CloseEvent (DnsSb->Timer);
206 }
207
208 FreePool (DnsSb);
209 }
210
211 /**
212 Create then initialize a Dns service binding instance.
213
214 @param Controller The controller to install the DNS service
215 binding on
216 @param Image The driver binding image of the DNS driver
217 @param IpVersion IpVersion for this service
218 @param Service The variable to receive the created service
219 binding instance.
220
221 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance.
222 @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
223 connection with UDP.
224 @retval EFI_SUCCESS The service instance is created for the
225 controller.
226
227 **/
228 EFI_STATUS
229 DnsCreateService (
230 IN EFI_HANDLE Controller,
231 IN EFI_HANDLE Image,
232 IN UINT8 IpVersion,
233 OUT DNS_SERVICE **Service
234 )
235 {
236 EFI_STATUS Status;
237 DNS_SERVICE *DnsSb;
238
239 Status = EFI_SUCCESS;
240 DnsSb = NULL;
241
242 *Service = NULL;
243
244 DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE));
245 if (DnsSb == NULL) {
246 return EFI_OUT_OF_RESOURCES;
247 }
248
249 DnsSb->Signature = DNS_SERVICE_SIGNATURE;
250
251 if (IpVersion == IP_VERSION_4) {
252 DnsSb->ServiceBinding = mDns4ServiceBinding;
253 } else {
254 DnsSb->ServiceBinding = mDns6ServiceBinding;
255 }
256
257 DnsSb->Dns4ChildrenNum = 0;
258 InitializeListHead (&DnsSb->Dns4ChildrenList);
259
260 DnsSb->Dns6ChildrenNum = 0;
261 InitializeListHead (&DnsSb->Dns6ChildrenList);
262
263 DnsSb->ControllerHandle = Controller;
264 DnsSb->ImageHandle = Image;
265
266 DnsSb->TimerToGetMap = NULL;
267
268 DnsSb->Timer = NULL;
269
270 DnsSb->IpVersion = IpVersion;
271
272 //
273 // Create the timer used to time out the procedure which is used to
274 // get the default IP address.
275 //
276 Status = gBS->CreateEvent (
277 EVT_TIMER,
278 TPL_CALLBACK,
279 NULL,
280 NULL,
281 &DnsSb->TimerToGetMap
282 );
283 if (EFI_ERROR (Status)) {
284 FreePool (DnsSb);
285 return Status;
286 }
287
288 //
289 // Create the timer to retransmit packets.
290 //
291 Status = gBS->CreateEvent (
292 EVT_NOTIFY_SIGNAL | EVT_TIMER,
293 TPL_CALLBACK,
294 DnsOnTimerRetransmit,
295 DnsSb,
296 &DnsSb->Timer
297 );
298 if (EFI_ERROR (Status)) {
299 if (DnsSb->TimerToGetMap != NULL) {
300 gBS->CloseEvent (DnsSb->TimerToGetMap);
301 }
302 FreePool (DnsSb);
303 return Status;
304 }
305
306 DnsSb->ConnectUdp = NULL;
307 DnsSb->ConnectUdp = UdpIoCreateIo (
308 Controller,
309 Image,
310 DnsConfigNullUdp,
311 DnsSb->IpVersion,
312 NULL
313 );
314 if (DnsSb->ConnectUdp == NULL) {
315 if (DnsSb->TimerToGetMap != NULL) {
316 gBS->CloseEvent (DnsSb->TimerToGetMap);
317 }
318 gBS->CloseEvent (DnsSb->Timer);
319 FreePool (DnsSb);
320 return EFI_DEVICE_ERROR;
321 }
322
323 *Service = DnsSb;
324 return Status;
325 }
326
327 /**
328 Unloads an image.
329
330 @param ImageHandle Handle that identifies the image to be unloaded.
331
332 @retval EFI_SUCCESS The image has been unloaded.
333 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
334
335 **/
336 EFI_STATUS
337 EFIAPI
338 DnsUnload (
339 IN EFI_HANDLE ImageHandle
340 )
341 {
342 EFI_STATUS Status;
343
344 LIST_ENTRY *Entry;
345 DNS4_CACHE *ItemCache4;
346 DNS4_SERVER_IP *ItemServerIp4;
347 DNS6_CACHE *ItemCache6;
348 DNS6_SERVER_IP *ItemServerIp6;
349
350 ItemCache4 = NULL;
351 ItemServerIp4 = NULL;
352 ItemCache6 = NULL;
353 ItemServerIp6 = NULL;
354
355 //
356 // Disconnect the driver specified by ImageHandle
357 //
358 Status = NetLibDefaultUnload(ImageHandle);
359 if (EFI_ERROR (Status)) {
360 return Status;
361 }
362
363 //
364 // Free mDriverData.
365 //
366 if (mDriverData != NULL) {
367 if (mDriverData->Timer != NULL) {
368 gBS->CloseEvent (mDriverData->Timer);
369 }
370
371 while (!IsListEmpty (&mDriverData->Dns4CacheList)) {
372 Entry = NetListRemoveHead (&mDriverData->Dns4CacheList);
373 ASSERT (Entry != NULL);
374 ItemCache4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
375 FreePool (ItemCache4->DnsCache.HostName);
376 FreePool (ItemCache4->DnsCache.IpAddress);
377 FreePool (ItemCache4);
378 }
379
380 while (!IsListEmpty (&mDriverData->Dns4ServerList)) {
381 Entry = NetListRemoveHead (&mDriverData->Dns4ServerList);
382 ASSERT (Entry != NULL);
383 ItemServerIp4 = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
384 FreePool (ItemServerIp4);
385 }
386
387 while (!IsListEmpty (&mDriverData->Dns6CacheList)) {
388 Entry = NetListRemoveHead (&mDriverData->Dns6CacheList);
389 ASSERT (Entry != NULL);
390 ItemCache6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
391 FreePool (ItemCache6->DnsCache.HostName);
392 FreePool (ItemCache6->DnsCache.IpAddress);
393 FreePool (ItemCache6);
394 }
395
396 while (!IsListEmpty (&mDriverData->Dns6ServerList)) {
397 Entry = NetListRemoveHead (&mDriverData->Dns6ServerList);
398 ASSERT (Entry != NULL);
399 ItemServerIp6 = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
400 FreePool (ItemServerIp6);
401 }
402
403 FreePool (mDriverData);
404 }
405
406 return Status;
407 }
408
409 /**
410 This is the declaration of an EFI image entry point. This entry point is
411 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
412 both device drivers and bus drivers.
413
414 @param ImageHandle The firmware allocated handle for the UEFI image.
415 @param SystemTable A pointer to the EFI System Table.
416
417 @retval EFI_SUCCESS The operation completed successfully.
418 @retval Others An unexpected error occurred.
419 **/
420 EFI_STATUS
421 EFIAPI
422 DnsDriverEntryPoint (
423 IN EFI_HANDLE ImageHandle,
424 IN EFI_SYSTEM_TABLE *SystemTable
425 )
426 {
427 EFI_STATUS Status;
428
429 Status = EFI_SUCCESS;
430
431 //
432 // Install the Dns4 Driver Binding Protocol.
433 //
434 Status = EfiLibInstallDriverBindingComponentName2 (
435 ImageHandle,
436 SystemTable,
437 &gDns4DriverBinding,
438 ImageHandle,
439 &gDnsComponentName,
440 &gDnsComponentName2
441 );
442 if (EFI_ERROR (Status)) {
443 return Status;
444 }
445
446 //
447 // Install the Dns6 Driver Binding Protocol.
448 //
449 Status = EfiLibInstallDriverBindingComponentName2 (
450 ImageHandle,
451 SystemTable,
452 &gDns6DriverBinding,
453 NULL,
454 &gDnsComponentName,
455 &gDnsComponentName2
456 );
457 if (EFI_ERROR (Status)) {
458 goto Error1;
459 }
460
461 //
462 // Create the driver data structures.
463 //
464 mDriverData = AllocateZeroPool (sizeof (DNS_DRIVER_DATA));
465 if (mDriverData == NULL) {
466 Status = EFI_OUT_OF_RESOURCES;
467 goto Error2;
468 }
469
470 //
471 // Create the timer event to update DNS cache list.
472 //
473 Status = gBS->CreateEvent (
474 EVT_NOTIFY_SIGNAL | EVT_TIMER,
475 TPL_CALLBACK,
476 DnsOnTimerUpdate,
477 NULL,
478 &mDriverData->Timer
479 );
480 if (EFI_ERROR (Status)) {
481 goto Error3;
482 }
483
484 Status = gBS->SetTimer (mDriverData->Timer, TimerPeriodic, TICKS_PER_SECOND);
485 if (EFI_ERROR (Status)) {
486 goto Error4;
487 }
488
489 InitializeListHead (&mDriverData->Dns4CacheList);
490 InitializeListHead (&mDriverData->Dns4ServerList);
491 InitializeListHead (&mDriverData->Dns6CacheList);
492 InitializeListHead (&mDriverData->Dns6ServerList);
493
494 return Status;
495
496 Error4:
497 gBS->CloseEvent (mDriverData->Timer);
498
499 Error3:
500 FreePool (mDriverData);
501
502 Error2:
503 EfiLibUninstallDriverBindingComponentName2 (
504 &gDns6DriverBinding,
505 &gDnsComponentName,
506 &gDnsComponentName2
507 );
508
509 Error1:
510 EfiLibUninstallDriverBindingComponentName2 (
511 &gDns4DriverBinding,
512 &gDnsComponentName,
513 &gDnsComponentName2
514 );
515
516 return Status;
517 }
518
519 /**
520 Tests to see if this driver supports a given controller. If a child device is provided,
521 it further tests to see if this driver supports creating a handle for the specified child device.
522
523 This function checks to see if the driver specified by This supports the device specified by
524 ControllerHandle. Drivers will typically use the device path attached to
525 ControllerHandle and/or the services from the bus I/O abstraction attached to
526 ControllerHandle to determine if the driver supports ControllerHandle. This function
527 may be called many times during platform initialization. In order to reduce boot times, the tests
528 performed by this function must be very small, and take as little time as possible to execute. This
529 function must not change the state of any hardware devices, and this function must be aware that the
530 device specified by ControllerHandle may already be managed by the same driver or a
531 different driver. This function must match its calls to AllocatePages() with FreePages(),
532 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
533 Because ControllerHandle may have been previously started by the same driver, if a protocol is
534 already in the opened state, then it must not be closed with CloseProtocol(). This is required
535 to guarantee the state of ControllerHandle is not modified by this function.
536
537 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
538 @param[in] ControllerHandle The handle of the controller to test. This handle
539 must support a protocol interface that supplies
540 an I/O abstraction to the driver.
541 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
542 parameter is ignored by device drivers, and is optional for bus
543 drivers. For bus drivers, if this parameter is not NULL, then
544 the bus driver must determine if the bus controller specified
545 by ControllerHandle and the child controller specified
546 by RemainingDevicePath are both supported by this
547 bus driver.
548
549 @retval EFI_SUCCESS The device specified by ControllerHandle and
550 RemainingDevicePath is supported by the driver specified by This.
551 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
552 RemainingDevicePath is already being managed by the driver
553 specified by This.
554 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
555 RemainingDevicePath is already being managed by a different
556 driver or an application that requires exclusive access.
557 Currently not implemented.
558 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
559 RemainingDevicePath is not supported by the driver specified by This.
560 **/
561 EFI_STATUS
562 EFIAPI
563 Dns4DriverBindingSupported (
564 IN EFI_DRIVER_BINDING_PROTOCOL *This,
565 IN EFI_HANDLE ControllerHandle,
566 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
567 )
568 {
569 EFI_STATUS Status;
570
571 //
572 // Test for the Dns4ServiceBinding Protocol.
573 //
574 Status = gBS->OpenProtocol (
575 ControllerHandle,
576 &gEfiDns4ServiceBindingProtocolGuid,
577 NULL,
578 This->DriverBindingHandle,
579 ControllerHandle,
580 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
581 );
582 if (!EFI_ERROR (Status)) {
583 return EFI_ALREADY_STARTED;
584 }
585
586 //
587 // Test for the Udp4ServiceBinding Protocol.
588 //
589 Status = gBS->OpenProtocol (
590 ControllerHandle,
591 &gEfiUdp4ServiceBindingProtocolGuid,
592 NULL,
593 This->DriverBindingHandle,
594 ControllerHandle,
595 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
596 );
597
598 return Status;
599 }
600
601 /**
602 Starts a device controller or a bus controller.
603
604 The Start() function is designed to be invoked from the EFI boot service ConnectController().
605 As a result, much of the error checking on the parameters to Start() has been moved into this
606 common boot service. It is legal to call Start() from other locations,
607 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
608 1. ControllerHandle must be a valid EFI_HANDLE.
609 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
610 EFI_DEVICE_PATH_PROTOCOL.
611 3. Prior to calling Start(), the Supported() function for the driver specified by This must
612 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
613
614 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
615 @param[in] ControllerHandle The handle of the controller to start. This handle
616 must support a protocol interface that supplies
617 an I/O abstraction to the driver.
618 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
619 parameter is ignored by device drivers, and is optional for bus
620 drivers. For a bus driver, if this parameter is NULL, then handles
621 for all the children of Controller are created by this driver.
622 If this parameter is not NULL and the first Device Path Node is
623 not the End of Device Path Node, then only the handle for the
624 child device specified by the first Device Path Node of
625 RemainingDevicePath is created by this driver.
626 If the first Device Path Node of RemainingDevicePath is
627 the End of Device Path Node, no child handle is created by this
628 driver.
629
630 @retval EFI_SUCCESS The device was started.
631 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
632 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
633 @retval Others The driver failded to start the device.
634
635 **/
636 EFI_STATUS
637 EFIAPI
638 Dns4DriverBindingStart (
639 IN EFI_DRIVER_BINDING_PROTOCOL *This,
640 IN EFI_HANDLE ControllerHandle,
641 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
642 )
643 {
644 DNS_SERVICE *DnsSb;
645 EFI_STATUS Status;
646
647 Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4, &DnsSb);
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651
652 ASSERT (DnsSb != NULL);
653
654 Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
655 if (EFI_ERROR (Status)) {
656 goto ON_ERROR;
657 }
658
659 //
660 // Install the Dns4ServiceBinding Protocol onto ControllerHandle.
661 //
662 Status = gBS->InstallMultipleProtocolInterfaces (
663 &ControllerHandle,
664 &gEfiDns4ServiceBindingProtocolGuid,
665 &DnsSb->ServiceBinding,
666 NULL
667 );
668 if (EFI_ERROR (Status)) {
669 goto ON_ERROR;
670 }
671
672 return EFI_SUCCESS;
673
674 ON_ERROR:
675 DnsDestroyService (DnsSb);
676
677 return Status;
678 }
679
680 /**
681 Stops a device controller or a bus controller.
682
683 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
684 As a result, much of the error checking on the parameters to Stop() has been moved
685 into this common boot service. It is legal to call Stop() from other locations,
686 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
687 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
688 same driver's Start() function.
689 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
690 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
691 Start() function, and the Start() function must have called OpenProtocol() on
692 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
693
694 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
695 @param[in] ControllerHandle A handle to the device being stopped. The handle must
696 support a bus specific I/O protocol for the driver
697 to use to stop the device.
698 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
699 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
700 if NumberOfChildren is 0.
701
702 @retval EFI_SUCCESS The device was stopped.
703 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
704
705 **/
706 EFI_STATUS
707 EFIAPI
708 Dns4DriverBindingStop (
709 IN EFI_DRIVER_BINDING_PROTOCOL *This,
710 IN EFI_HANDLE ControllerHandle,
711 IN UINTN NumberOfChildren,
712 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
713 )
714 {
715 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
716 DNS_SERVICE *DnsSb;
717 EFI_HANDLE NicHandle;
718 EFI_STATUS Status;
719 LIST_ENTRY *List;
720 DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
721
722 //
723 // DNS driver opens UDP child, So, Controller is a UDP
724 // child handle. Locate the Nic handle first. Then get the
725 // DNS private data back.
726 //
727 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
728
729 if (NicHandle == NULL) {
730 return EFI_SUCCESS;
731 }
732
733 Status = gBS->OpenProtocol (
734 NicHandle,
735 &gEfiDns4ServiceBindingProtocolGuid,
736 (VOID **) &ServiceBinding,
737 This->DriverBindingHandle,
738 NicHandle,
739 EFI_OPEN_PROTOCOL_GET_PROTOCOL
740 );
741 if (EFI_ERROR (Status)) {
742 return EFI_DEVICE_ERROR;
743 }
744
745 DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
746
747 if (!IsListEmpty (&DnsSb->Dns4ChildrenList)) {
748 //
749 // Destroy the Dns child instance in ChildHandleBuffer.
750 //
751 List = &DnsSb->Dns4ChildrenList;
752 Context.ServiceBinding = ServiceBinding;
753 Context.NumberOfChildren = NumberOfChildren;
754 Context.ChildHandleBuffer = ChildHandleBuffer;
755 Status = NetDestroyLinkList (
756 List,
757 DnsDestroyChildEntryInHandleBuffer,
758 &Context,
759 NULL
760 );
761 }
762
763 if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns4ChildrenList)) {
764 gBS->UninstallProtocolInterface (
765 NicHandle,
766 &gEfiDns4ServiceBindingProtocolGuid,
767 ServiceBinding
768 );
769
770 DnsDestroyService (DnsSb);
771
772 if (gDnsControllerNameTable != NULL) {
773 FreeUnicodeStringTable (gDnsControllerNameTable);
774 gDnsControllerNameTable = NULL;
775 }
776
777 Status = EFI_SUCCESS;
778 }
779
780 return Status;
781 }
782
783 /**
784 Tests to see if this driver supports a given controller. If a child device is provided,
785 it further tests to see if this driver supports creating a handle for the specified child device.
786
787 This function checks to see if the driver specified by This supports the device specified by
788 ControllerHandle. Drivers will typically use the device path attached to
789 ControllerHandle and/or the services from the bus I/O abstraction attached to
790 ControllerHandle to determine if the driver supports ControllerHandle. This function
791 may be called many times during platform initialization. In order to reduce boot times, the tests
792 performed by this function must be very small, and take as little time as possible to execute. This
793 function must not change the state of any hardware devices, and this function must be aware that the
794 device specified by ControllerHandle may already be managed by the same driver or a
795 different driver. This function must match its calls to AllocatePages() with FreePages(),
796 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
797 Because ControllerHandle may have been previously started by the same driver, if a protocol is
798 already in the opened state, then it must not be closed with CloseProtocol(). This is required
799 to guarantee the state of ControllerHandle is not modified by this function.
800
801 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
802 @param[in] ControllerHandle The handle of the controller to test. This handle
803 must support a protocol interface that supplies
804 an I/O abstraction to the driver.
805 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
806 parameter is ignored by device drivers, and is optional for bus
807 drivers. For bus drivers, if this parameter is not NULL, then
808 the bus driver must determine if the bus controller specified
809 by ControllerHandle and the child controller specified
810 by RemainingDevicePath are both supported by this
811 bus driver.
812
813 @retval EFI_SUCCESS The device specified by ControllerHandle and
814 RemainingDevicePath is supported by the driver specified by This.
815 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
816 RemainingDevicePath is already being managed by the driver
817 specified by This.
818 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
819 RemainingDevicePath is already being managed by a different
820 driver or an application that requires exclusive access.
821 Currently not implemented.
822 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
823 RemainingDevicePath is not supported by the driver specified by This.
824 **/
825 EFI_STATUS
826 EFIAPI
827 Dns6DriverBindingSupported (
828 IN EFI_DRIVER_BINDING_PROTOCOL *This,
829 IN EFI_HANDLE ControllerHandle,
830 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
831 )
832 {
833 EFI_STATUS Status;
834
835 //
836 // Test for the Dns6ServiceBinding Protocol
837 //
838 Status = gBS->OpenProtocol (
839 ControllerHandle,
840 &gEfiDns6ServiceBindingProtocolGuid,
841 NULL,
842 This->DriverBindingHandle,
843 ControllerHandle,
844 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
845 );
846 if (!EFI_ERROR (Status)) {
847 return EFI_ALREADY_STARTED;
848 }
849
850 //
851 // Test for the Udp6ServiceBinding Protocol
852 //
853 Status = gBS->OpenProtocol (
854 ControllerHandle,
855 &gEfiUdp6ServiceBindingProtocolGuid,
856 NULL,
857 This->DriverBindingHandle,
858 ControllerHandle,
859 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
860 );
861
862 return Status;
863 }
864
865 /**
866 Starts a device controller or a bus controller.
867
868 The Start() function is designed to be invoked from the EFI boot service ConnectController().
869 As a result, much of the error checking on the parameters to Start() has been moved into this
870 common boot service. It is legal to call Start() from other locations,
871 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
872 1. ControllerHandle must be a valid EFI_HANDLE.
873 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
874 EFI_DEVICE_PATH_PROTOCOL.
875 3. Prior to calling Start(), the Supported() function for the driver specified by This must
876 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
877
878 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
879 @param[in] ControllerHandle The handle of the controller to start. This handle
880 must support a protocol interface that supplies
881 an I/O abstraction to the driver.
882 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
883 parameter is ignored by device drivers, and is optional for bus
884 drivers. For a bus driver, if this parameter is NULL, then handles
885 for all the children of Controller are created by this driver.
886 If this parameter is not NULL and the first Device Path Node is
887 not the End of Device Path Node, then only the handle for the
888 child device specified by the first Device Path Node of
889 RemainingDevicePath is created by this driver.
890 If the first Device Path Node of RemainingDevicePath is
891 the End of Device Path Node, no child handle is created by this
892 driver.
893
894 @retval EFI_SUCCESS The device was started.
895 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
896 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
897 @retval Others The driver failded to start the device.
898
899 **/
900 EFI_STATUS
901 EFIAPI
902 Dns6DriverBindingStart (
903 IN EFI_DRIVER_BINDING_PROTOCOL *This,
904 IN EFI_HANDLE ControllerHandle,
905 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
906 )
907 {
908 DNS_SERVICE *DnsSb;
909 EFI_STATUS Status;
910
911 Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6, &DnsSb);
912 if (EFI_ERROR (Status)) {
913 return Status;
914 }
915
916 ASSERT (DnsSb != NULL);
917
918 Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
919 if (EFI_ERROR (Status)) {
920 goto ON_ERROR;
921 }
922
923 //
924 // Install the Dns6ServiceBinding Protocol onto ControllerHandle
925 //
926 Status = gBS->InstallMultipleProtocolInterfaces (
927 &ControllerHandle,
928 &gEfiDns6ServiceBindingProtocolGuid,
929 &DnsSb->ServiceBinding,
930 NULL
931 );
932
933 if (EFI_ERROR (Status)) {
934 goto ON_ERROR;
935 }
936
937 return EFI_SUCCESS;
938
939 ON_ERROR:
940 DnsDestroyService (DnsSb);
941
942 return Status;
943 }
944
945 /**
946 Stops a device controller or a bus controller.
947
948 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
949 As a result, much of the error checking on the parameters to Stop() has been moved
950 into this common boot service. It is legal to call Stop() from other locations,
951 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
952 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
953 same driver's Start() function.
954 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
955 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
956 Start() function, and the Start() function must have called OpenProtocol() on
957 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
958
959 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
960 @param[in] ControllerHandle A handle to the device being stopped. The handle must
961 support a bus specific I/O protocol for the driver
962 to use to stop the device.
963 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
964 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
965 if NumberOfChildren is 0.
966
967 @retval EFI_SUCCESS The device was stopped.
968 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
969
970 **/
971 EFI_STATUS
972 EFIAPI
973 Dns6DriverBindingStop (
974 IN EFI_DRIVER_BINDING_PROTOCOL *This,
975 IN EFI_HANDLE ControllerHandle,
976 IN UINTN NumberOfChildren,
977 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
978 )
979 {
980 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
981 DNS_SERVICE *DnsSb;
982 EFI_HANDLE NicHandle;
983 EFI_STATUS Status;
984 LIST_ENTRY *List;
985 DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
986
987 //
988 // DNS driver opens UDP child, So, Controller is a UDP
989 // child handle. Locate the Nic handle first. Then get the
990 // DNS private data back.
991 //
992 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);
993
994 if (NicHandle == NULL) {
995 return EFI_SUCCESS;
996 }
997
998 Status = gBS->OpenProtocol (
999 NicHandle,
1000 &gEfiDns6ServiceBindingProtocolGuid,
1001 (VOID **) &ServiceBinding,
1002 This->DriverBindingHandle,
1003 NicHandle,
1004 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1005 );
1006 if (EFI_ERROR (Status)) {
1007 return EFI_DEVICE_ERROR;
1008 }
1009
1010 DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding);
1011
1012 if (!IsListEmpty (&DnsSb->Dns6ChildrenList)) {
1013 //
1014 // Destroy the Dns child instance in ChildHandleBuffer.
1015 //
1016 List = &DnsSb->Dns6ChildrenList;
1017 Context.ServiceBinding = ServiceBinding;
1018 Context.NumberOfChildren = NumberOfChildren;
1019 Context.ChildHandleBuffer = ChildHandleBuffer;
1020 Status = NetDestroyLinkList (
1021 List,
1022 DnsDestroyChildEntryInHandleBuffer,
1023 &Context,
1024 NULL
1025 );
1026 }
1027
1028 if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns6ChildrenList)) {
1029 gBS->UninstallProtocolInterface (
1030 NicHandle,
1031 &gEfiDns6ServiceBindingProtocolGuid,
1032 ServiceBinding
1033 );
1034
1035 DnsDestroyService (DnsSb);
1036
1037 if (gDnsControllerNameTable != NULL) {
1038 FreeUnicodeStringTable (gDnsControllerNameTable);
1039 gDnsControllerNameTable = NULL;
1040 }
1041
1042 Status = EFI_SUCCESS;
1043 }
1044
1045 return Status;
1046 }
1047
1048 /**
1049 Creates a child handle and installs a protocol.
1050
1051 The CreateChild() function installs a protocol on ChildHandle.
1052 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
1053 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
1054
1055 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
1056 @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
1057 then a new handle is created. If it is a pointer to an existing UEFI handle,
1058 then the protocol is added to the existing UEFI handle.
1059
1060 @retval EFI_SUCCES The protocol was added to ChildHandle.
1061 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
1062 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
1063 the child
1064 @retval other The child handle was not created
1065
1066 **/
1067 EFI_STATUS
1068 EFIAPI
1069 Dns4ServiceBindingCreateChild (
1070 IN EFI_SERVICE_BINDING_PROTOCOL *This,
1071 IN EFI_HANDLE *ChildHandle
1072 )
1073 {
1074 DNS_SERVICE *DnsSb;
1075 DNS_INSTANCE *Instance;
1076 EFI_STATUS Status;
1077 EFI_TPL OldTpl;
1078 VOID *Udp4;
1079
1080 if ((This == NULL) || (ChildHandle == NULL)) {
1081 return EFI_INVALID_PARAMETER;
1082 }
1083
1084 DnsSb = DNS_SERVICE_FROM_THIS (This);
1085
1086 Status = DnsCreateInstance (DnsSb, &Instance);
1087 if (EFI_ERROR (Status)) {
1088 return Status;
1089 }
1090 ASSERT (Instance != NULL);
1091
1092 //
1093 // Install the DNS protocol onto ChildHandle
1094 //
1095 Status = gBS->InstallMultipleProtocolInterfaces (
1096 ChildHandle,
1097 &gEfiDns4ProtocolGuid,
1098 &Instance->Dns4,
1099 NULL
1100 );
1101 if (EFI_ERROR (Status)) {
1102 goto ON_ERROR;
1103 }
1104
1105 Instance->ChildHandle = *ChildHandle;
1106
1107 //
1108 // Open the Udp4 protocol BY_CHILD.
1109 //
1110 Status = gBS->OpenProtocol (
1111 DnsSb->ConnectUdp->UdpHandle,
1112 &gEfiUdp4ProtocolGuid,
1113 (VOID **) &Udp4,
1114 gDns4DriverBinding.DriverBindingHandle,
1115 Instance->ChildHandle,
1116 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1117 );
1118 if (EFI_ERROR (Status)) {
1119 gBS->UninstallMultipleProtocolInterfaces (
1120 Instance->ChildHandle,
1121 &gEfiDns4ProtocolGuid,
1122 &Instance->Dns4,
1123 NULL
1124 );
1125
1126 goto ON_ERROR;
1127 }
1128
1129 //
1130 // Open the Udp4 protocol by child.
1131 //
1132 Status = gBS->OpenProtocol (
1133 Instance->UdpIo->UdpHandle,
1134 &gEfiUdp4ProtocolGuid,
1135 (VOID **) &Udp4,
1136 gDns4DriverBinding.DriverBindingHandle,
1137 Instance->ChildHandle,
1138 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1139 );
1140 if (EFI_ERROR (Status)) {
1141 //
1142 // Close the Udp4 protocol.
1143 //
1144 gBS->CloseProtocol (
1145 DnsSb->ConnectUdp->UdpHandle,
1146 &gEfiUdp4ProtocolGuid,
1147 gDns4DriverBinding.DriverBindingHandle,
1148 ChildHandle
1149 );
1150
1151 gBS->UninstallMultipleProtocolInterfaces (
1152 Instance->ChildHandle,
1153 &gEfiDns4ProtocolGuid,
1154 &Instance->Dns4,
1155 NULL
1156 );
1157
1158 goto ON_ERROR;
1159 }
1160
1161 //
1162 // Add it to the parent's child list.
1163 //
1164 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1165
1166 InsertTailList (&DnsSb->Dns4ChildrenList, &Instance->Link);
1167 DnsSb->Dns4ChildrenNum++;
1168
1169 gBS->RestoreTPL (OldTpl);
1170
1171 return EFI_SUCCESS;
1172
1173 ON_ERROR:
1174
1175 DnsDestroyInstance (Instance);
1176 return Status;
1177 }
1178
1179 /**
1180 Destroys a child handle with a protocol installed on it.
1181
1182 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
1183 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
1184 last protocol on ChildHandle, then ChildHandle is destroyed.
1185
1186 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
1187 @param[in] ChildHandle Handle of the child to destroy
1188
1189 @retval EFI_SUCCES The protocol was removed from ChildHandle.
1190 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
1191 @retval EFI_INVALID_PARAMETER Child handle is NULL.
1192 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
1193 because its services are being used.
1194 @retval other The child handle was not destroyed
1195
1196 **/
1197 EFI_STATUS
1198 EFIAPI
1199 Dns4ServiceBindingDestroyChild (
1200 IN EFI_SERVICE_BINDING_PROTOCOL *This,
1201 IN EFI_HANDLE ChildHandle
1202 )
1203 {
1204 DNS_SERVICE *DnsSb;
1205 DNS_INSTANCE *Instance;
1206
1207 EFI_DNS4_PROTOCOL *Dns4;
1208 EFI_STATUS Status;
1209 EFI_TPL OldTpl;
1210
1211 if ((This == NULL) || (ChildHandle == NULL)) {
1212 return EFI_INVALID_PARAMETER;
1213 }
1214
1215 //
1216 // Retrieve the private context data structures
1217 //
1218 Status = gBS->OpenProtocol (
1219 ChildHandle,
1220 &gEfiDns4ProtocolGuid,
1221 (VOID **) &Dns4,
1222 gDns4DriverBinding.DriverBindingHandle,
1223 ChildHandle,
1224 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1225 );
1226
1227 if (EFI_ERROR (Status)) {
1228 return EFI_UNSUPPORTED;
1229 }
1230
1231 Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (Dns4);
1232 DnsSb = DNS_SERVICE_FROM_THIS (This);
1233
1234 if (Instance->Service != DnsSb) {
1235 return EFI_INVALID_PARAMETER;
1236 }
1237
1238 if (Instance->InDestroy) {
1239 return EFI_SUCCESS;
1240 }
1241
1242 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1243
1244 Instance->InDestroy = TRUE;
1245
1246 //
1247 // Close the Udp4 protocol.
1248 //
1249 gBS->CloseProtocol (
1250 DnsSb->ConnectUdp->UdpHandle,
1251 &gEfiUdp4ProtocolGuid,
1252 gDns4DriverBinding.DriverBindingHandle,
1253 ChildHandle
1254 );
1255
1256 gBS->CloseProtocol (
1257 Instance->UdpIo->UdpHandle,
1258 &gEfiUdp4ProtocolGuid,
1259 gDns4DriverBinding.DriverBindingHandle,
1260 ChildHandle
1261 );
1262
1263 gBS->RestoreTPL (OldTpl);
1264
1265 //
1266 // Uninstall the DNS protocol first to enable a top down destruction.
1267 //
1268 Status = gBS->UninstallProtocolInterface (
1269 ChildHandle,
1270 &gEfiDns4ProtocolGuid,
1271 Dns4
1272 );
1273
1274 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1275
1276 if (EFI_ERROR (Status)) {
1277 Instance->InDestroy = FALSE;
1278 gBS->RestoreTPL (OldTpl);
1279 return Status;
1280 }
1281
1282 RemoveEntryList (&Instance->Link);
1283 DnsSb->Dns4ChildrenNum--;
1284
1285 gBS->RestoreTPL (OldTpl);
1286
1287 DnsDestroyInstance (Instance);
1288 return EFI_SUCCESS;
1289 }
1290
1291 /**
1292 Creates a child handle and installs a protocol.
1293
1294 The CreateChild() function installs a protocol on ChildHandle.
1295 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
1296 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
1297
1298 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
1299 @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
1300 then a new handle is created. If it is a pointer to an existing UEFI handle,
1301 then the protocol is added to the existing UEFI handle.
1302
1303 @retval EFI_SUCCES The protocol was added to ChildHandle.
1304 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
1305 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
1306 the child
1307 @retval other The child handle was not created
1308
1309 **/
1310 EFI_STATUS
1311 EFIAPI
1312 Dns6ServiceBindingCreateChild (
1313 IN EFI_SERVICE_BINDING_PROTOCOL *This,
1314 IN EFI_HANDLE *ChildHandle
1315 )
1316 {
1317 DNS_SERVICE *DnsSb;
1318 DNS_INSTANCE *Instance;
1319 EFI_STATUS Status;
1320 EFI_TPL OldTpl;
1321 VOID *Udp6;
1322
1323 if ((This == NULL) || (ChildHandle == NULL)) {
1324 return EFI_INVALID_PARAMETER;
1325 }
1326
1327 DnsSb = DNS_SERVICE_FROM_THIS (This);
1328
1329 Status = DnsCreateInstance (DnsSb, &Instance);
1330 if (EFI_ERROR (Status)) {
1331 return Status;
1332 }
1333 ASSERT (Instance != NULL);
1334
1335 //
1336 // Install the DNS protocol onto ChildHandle
1337 //
1338 Status = gBS->InstallMultipleProtocolInterfaces (
1339 ChildHandle,
1340 &gEfiDns6ProtocolGuid,
1341 &Instance->Dns6,
1342 NULL
1343 );
1344 if (EFI_ERROR (Status)) {
1345 goto ON_ERROR;
1346 }
1347
1348 Instance->ChildHandle = *ChildHandle;
1349
1350 //
1351 // Open the Udp6 protocol BY_CHILD.
1352 //
1353 Status = gBS->OpenProtocol (
1354 DnsSb->ConnectUdp->UdpHandle,
1355 &gEfiUdp6ProtocolGuid,
1356 (VOID **) &Udp6,
1357 gDns6DriverBinding.DriverBindingHandle,
1358 Instance->ChildHandle,
1359 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1360 );
1361 if (EFI_ERROR (Status)) {
1362 gBS->UninstallMultipleProtocolInterfaces (
1363 Instance->ChildHandle,
1364 &gEfiDns6ProtocolGuid,
1365 &Instance->Dns6,
1366 NULL
1367 );
1368
1369 goto ON_ERROR;
1370 }
1371
1372 //
1373 // Open the Udp6 protocol by child.
1374 //
1375 Status = gBS->OpenProtocol (
1376 Instance->UdpIo->UdpHandle,
1377 &gEfiUdp6ProtocolGuid,
1378 (VOID **) &Udp6,
1379 gDns6DriverBinding.DriverBindingHandle,
1380 Instance->ChildHandle,
1381 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1382 );
1383 if (EFI_ERROR (Status)) {
1384 //
1385 // Close the Udp6 protocol.
1386 //
1387 gBS->CloseProtocol (
1388 DnsSb->ConnectUdp->UdpHandle,
1389 &gEfiUdp6ProtocolGuid,
1390 gDns6DriverBinding.DriverBindingHandle,
1391 ChildHandle
1392 );
1393
1394 gBS->UninstallMultipleProtocolInterfaces (
1395 Instance->ChildHandle,
1396 &gEfiDns6ProtocolGuid,
1397 &Instance->Dns6,
1398 NULL
1399 );
1400
1401 goto ON_ERROR;
1402 }
1403
1404 //
1405 // Add it to the parent's child list.
1406 //
1407 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1408
1409 InsertTailList (&DnsSb->Dns6ChildrenList, &Instance->Link);
1410 DnsSb->Dns6ChildrenNum++;
1411
1412 gBS->RestoreTPL (OldTpl);
1413
1414 return EFI_SUCCESS;
1415
1416 ON_ERROR:
1417
1418 DnsDestroyInstance (Instance);
1419 return Status;
1420 }
1421
1422 /**
1423 Destroys a child handle with a protocol installed on it.
1424
1425 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
1426 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
1427 last protocol on ChildHandle, then ChildHandle is destroyed.
1428
1429 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
1430 @param[in] ChildHandle Handle of the child to destroy
1431
1432 @retval EFI_SUCCES The protocol was removed from ChildHandle.
1433 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
1434 @retval EFI_INVALID_PARAMETER Child handle is NULL.
1435 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
1436 because its services are being used.
1437 @retval other The child handle was not destroyed
1438
1439 **/
1440 EFI_STATUS
1441 EFIAPI
1442 Dns6ServiceBindingDestroyChild (
1443 IN EFI_SERVICE_BINDING_PROTOCOL *This,
1444 IN EFI_HANDLE ChildHandle
1445 )
1446 {
1447 DNS_SERVICE *DnsSb;
1448 DNS_INSTANCE *Instance;
1449
1450 EFI_DNS6_PROTOCOL *Dns6;
1451 EFI_STATUS Status;
1452 EFI_TPL OldTpl;
1453
1454 if ((This == NULL) || (ChildHandle == NULL)) {
1455 return EFI_INVALID_PARAMETER;
1456 }
1457
1458 //
1459 // Retrieve the private context data structures
1460 //
1461 Status = gBS->OpenProtocol (
1462 ChildHandle,
1463 &gEfiDns6ProtocolGuid,
1464 (VOID **) &Dns6,
1465 gDns6DriverBinding.DriverBindingHandle,
1466 ChildHandle,
1467 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1468 );
1469
1470 if (EFI_ERROR (Status)) {
1471 return EFI_UNSUPPORTED;
1472 }
1473
1474 Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (Dns6);
1475 DnsSb = DNS_SERVICE_FROM_THIS (This);
1476
1477 if (Instance->Service != DnsSb) {
1478 return EFI_INVALID_PARAMETER;
1479 }
1480
1481 if (Instance->InDestroy) {
1482 return EFI_SUCCESS;
1483 }
1484
1485 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1486
1487 Instance->InDestroy = TRUE;
1488
1489 //
1490 // Close the Udp6 protocol.
1491 //
1492 gBS->CloseProtocol (
1493 DnsSb->ConnectUdp->UdpHandle,
1494 &gEfiUdp6ProtocolGuid,
1495 gDns6DriverBinding.DriverBindingHandle,
1496 ChildHandle
1497 );
1498
1499 gBS->CloseProtocol (
1500 Instance->UdpIo->UdpHandle,
1501 &gEfiUdp6ProtocolGuid,
1502 gDns6DriverBinding.DriverBindingHandle,
1503 ChildHandle
1504 );
1505
1506 gBS->RestoreTPL (OldTpl);
1507
1508 //
1509 // Uninstall the DNS protocol first to enable a top down destruction.
1510 //
1511 Status = gBS->UninstallProtocolInterface (
1512 ChildHandle,
1513 &gEfiDns6ProtocolGuid,
1514 Dns6
1515 );
1516
1517 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1518
1519 if (EFI_ERROR (Status)) {
1520 Instance->InDestroy = FALSE;
1521 gBS->RestoreTPL (OldTpl);
1522 return Status;
1523 }
1524
1525 RemoveEntryList (&Instance->Link);
1526 DnsSb->Dns6ChildrenNum--;
1527
1528 gBS->RestoreTPL (OldTpl);
1529
1530 DnsDestroyInstance (Instance);
1531 return EFI_SUCCESS;
1532 }