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