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