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