| /** @file | |
| The driver binding and service binding protocol for DnsDxe driver. | |
| Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "DnsImpl.h" | |
| EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding = { | |
| Dns4DriverBindingSupported, | |
| Dns4DriverBindingStart, | |
| Dns4DriverBindingStop, | |
| DNS_VERSION, | |
| NULL, | |
| NULL | |
| }; | |
| EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding = { | |
| Dns6DriverBindingSupported, | |
| Dns6DriverBindingStart, | |
| Dns6DriverBindingStop, | |
| DNS_VERSION, | |
| NULL, | |
| NULL | |
| }; | |
| EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding = { | |
| Dns4ServiceBindingCreateChild, | |
| Dns4ServiceBindingDestroyChild | |
| }; | |
| EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding = { | |
| Dns6ServiceBindingCreateChild, | |
| Dns6ServiceBindingDestroyChild | |
| }; | |
| DNS_DRIVER_DATA *mDriverData = NULL; | |
| /** | |
| Destroy the DNS instance and recycle the resources. | |
| @param[in] Instance The pointer to the DNS instance. | |
| **/ | |
| VOID | |
| DnsDestroyInstance ( | |
| IN DNS_INSTANCE *Instance | |
| ) | |
| { | |
| ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA)); | |
| ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA)); | |
| if (!NetMapIsEmpty (&Instance->Dns4TxTokens)) { | |
| Dns4InstanceCancelToken (Instance, NULL); | |
| } | |
| if (!NetMapIsEmpty (&Instance->Dns6TxTokens)) { | |
| Dns6InstanceCancelToken (Instance, NULL); | |
| } | |
| if (Instance->UdpIo!= NULL) { | |
| UdpIoFreeIo (Instance->UdpIo); | |
| } | |
| FreePool (Instance); | |
| } | |
| /** | |
| Create the DNS instance and initialize it. | |
| @param[in] Service The pointer to the DNS service. | |
| @param[out] Instance The pointer to the DNS instance. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
| @retval EFI_SUCCESS The DNS instance is created. | |
| **/ | |
| EFI_STATUS | |
| DnsCreateInstance ( | |
| IN DNS_SERVICE *Service, | |
| OUT DNS_INSTANCE **Instance | |
| ) | |
| { | |
| DNS_INSTANCE *DnsIns; | |
| *Instance = NULL; | |
| DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE)); | |
| if (DnsIns == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| DnsIns->Signature = DNS_INSTANCE_SIGNATURE; | |
| InitializeListHead (&DnsIns->Link); | |
| DnsIns->State = DNS_STATE_UNCONFIGED; | |
| DnsIns->InDestroy = FALSE; | |
| DnsIns->Service = Service; | |
| if (Service->IpVersion == IP_VERSION_4) { | |
| CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4)); | |
| NetMapInit (&DnsIns->Dns4TxTokens); | |
| } else { | |
| CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6)); | |
| NetMapInit (&DnsIns->Dns6TxTokens); | |
| } | |
| DnsIns->UdpIo = UdpIoCreateIo ( | |
| Service->ControllerHandle, /// NicHandle | |
| Service->ImageHandle, | |
| DnsConfigNullUdp, | |
| Service->IpVersion, | |
| DnsIns | |
| ); | |
| if (DnsIns->UdpIo == NULL) { | |
| FreePool (DnsIns); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| *Instance = DnsIns; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Callback function which provided by user to remove one node in NetDestroyLinkList process. | |
| @param[in] Entry The entry to be removed. | |
| @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. | |
| @retval EFI_SUCCESS The entry has been removed successfully. | |
| @retval Others Fail to remove the entry. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DnsDestroyChildEntryInHandleBuffer ( | |
| IN LIST_ENTRY *Entry, | |
| IN VOID *Context | |
| ) | |
| { | |
| DNS_INSTANCE *Instance; | |
| EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; | |
| UINTN NumberOfChildren; | |
| EFI_HANDLE *ChildHandleBuffer; | |
| if (Entry == NULL || Context == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Instance = NET_LIST_USER_STRUCT_S (Entry, DNS_INSTANCE, Link, DNS_INSTANCE_SIGNATURE); | |
| ServiceBinding = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding; | |
| NumberOfChildren = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren; | |
| ChildHandleBuffer = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer; | |
| if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) { | |
| return EFI_SUCCESS; | |
| } | |
| return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle); | |
| } | |
| /** | |
| Config a NULL UDP that is used to keep the connection between UDP and DNS. | |
| Just leave the Udp child unconfigured. When UDP is unloaded, | |
| DNS will be informed with DriverBinding Stop. | |
| @param UdpIo The UDP_IO to configure | |
| @param Context The opaque parameter to the callback | |
| @retval EFI_SUCCESS It always return EFI_SUCCESS directly. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DnsConfigNullUdp ( | |
| IN UDP_IO *UdpIo, | |
| IN VOID *Context | |
| ) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Release all the resource used the DNS service binding instance. | |
| @param DnsSb The Dns service binding instance. | |
| **/ | |
| VOID | |
| DnsDestroyService ( | |
| IN DNS_SERVICE *DnsSb | |
| ) | |
| { | |
| UdpIoFreeIo (DnsSb->ConnectUdp); | |
| if (DnsSb->TimerToGetMap != NULL){ | |
| gBS->CloseEvent (DnsSb->TimerToGetMap); | |
| } | |
| if (DnsSb->Timer != NULL){ | |
| gBS->CloseEvent (DnsSb->Timer); | |
| } | |
| FreePool (DnsSb); | |
| } | |
| /** | |
| Create then initialize a Dns service binding instance. | |
| @param Controller The controller to install the DNS service | |
| binding on | |
| @param Image The driver binding image of the DNS driver | |
| @param IpVersion IpVersion for this service | |
| @param Service The variable to receive the created service | |
| binding instance. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance. | |
| @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep | |
| connection with UDP. | |
| @retval EFI_SUCCESS The service instance is created for the | |
| controller. | |
| **/ | |
| EFI_STATUS | |
| DnsCreateService ( | |
| IN EFI_HANDLE Controller, | |
| IN EFI_HANDLE Image, | |
| IN UINT8 IpVersion, | |
| OUT DNS_SERVICE **Service | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| DNS_SERVICE *DnsSb; | |
| Status = EFI_SUCCESS; | |
| DnsSb = NULL; | |
| *Service = NULL; | |
| DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE)); | |
| if (DnsSb == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| DnsSb->Signature = DNS_SERVICE_SIGNATURE; | |
| if (IpVersion == IP_VERSION_4) { | |
| DnsSb->ServiceBinding = mDns4ServiceBinding; | |
| } else { | |
| DnsSb->ServiceBinding = mDns6ServiceBinding; | |
| } | |
| DnsSb->Dns4ChildrenNum = 0; | |
| InitializeListHead (&DnsSb->Dns4ChildrenList); | |
| DnsSb->Dns6ChildrenNum = 0; | |
| InitializeListHead (&DnsSb->Dns6ChildrenList); | |
| DnsSb->ControllerHandle = Controller; | |
| DnsSb->ImageHandle = Image; | |
| DnsSb->TimerToGetMap = NULL; | |
| DnsSb->Timer = NULL; | |
| DnsSb->IpVersion = IpVersion; | |
| // | |
| // Create the timer used to time out the procedure which is used to | |
| // get the default IP address. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_TIMER, | |
| TPL_CALLBACK, | |
| NULL, | |
| NULL, | |
| &DnsSb->TimerToGetMap | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (DnsSb); | |
| return Status; | |
| } | |
| // | |
| // Create the timer to retransmit packets. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL | EVT_TIMER, | |
| TPL_CALLBACK, | |
| DnsOnTimerRetransmit, | |
| DnsSb, | |
| &DnsSb->Timer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| if (DnsSb->TimerToGetMap != NULL) { | |
| gBS->CloseEvent (DnsSb->TimerToGetMap); | |
| } | |
| FreePool (DnsSb); | |
| return Status; | |
| } | |
| DnsSb->ConnectUdp = NULL; | |
| DnsSb->ConnectUdp = UdpIoCreateIo ( | |
| Controller, | |
| Image, | |
| DnsConfigNullUdp, | |
| DnsSb->IpVersion, | |
| NULL | |
| ); | |
| if (DnsSb->ConnectUdp == NULL) { | |
| if (DnsSb->TimerToGetMap != NULL) { | |
| gBS->CloseEvent (DnsSb->TimerToGetMap); | |
| } | |
| gBS->CloseEvent (DnsSb->Timer); | |
| FreePool (DnsSb); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| *Service = DnsSb; | |
| return Status; | |
| } | |
| /** | |
| Unloads an image. | |
| @param ImageHandle Handle that identifies the image to be unloaded. | |
| @retval EFI_SUCCESS The image has been unloaded. | |
| @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DnsUnload ( | |
| IN EFI_HANDLE ImageHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Entry; | |
| DNS4_CACHE *ItemCache4; | |
| DNS4_SERVER_IP *ItemServerIp4; | |
| DNS6_CACHE *ItemCache6; | |
| DNS6_SERVER_IP *ItemServerIp6; | |
| ItemCache4 = NULL; | |
| ItemServerIp4 = NULL; | |
| ItemCache6 = NULL; | |
| ItemServerIp6 = NULL; | |
| // | |
| // Disconnect the driver specified by ImageHandle | |
| // | |
| Status = NetLibDefaultUnload(ImageHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Free mDriverData. | |
| // | |
| if (mDriverData != NULL) { | |
| if (mDriverData->Timer != NULL) { | |
| gBS->CloseEvent (mDriverData->Timer); | |
| } | |
| while (!IsListEmpty (&mDriverData->Dns4CacheList)) { | |
| Entry = NetListRemoveHead (&mDriverData->Dns4CacheList); | |
| ItemCache4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); | |
| if (ItemCache4->DnsCache.HostName != NULL) { | |
| FreePool (ItemCache4->DnsCache.HostName); | |
| } | |
| if (ItemCache4->DnsCache.IpAddress != NULL) { | |
| FreePool (ItemCache4->DnsCache.IpAddress); | |
| } | |
| FreePool (ItemCache4); | |
| } | |
| while (!IsListEmpty (&mDriverData->Dns4ServerList)) { | |
| Entry = NetListRemoveHead (&mDriverData->Dns4ServerList); | |
| ItemServerIp4 = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink); | |
| FreePool (ItemServerIp4); | |
| } | |
| while (!IsListEmpty (&mDriverData->Dns6CacheList)) { | |
| Entry = NetListRemoveHead (&mDriverData->Dns6CacheList); | |
| ItemCache6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); | |
| if (ItemCache6->DnsCache.HostName != NULL) { | |
| FreePool (ItemCache6->DnsCache.HostName); | |
| } | |
| if (ItemCache6->DnsCache.IpAddress != NULL) { | |
| FreePool (ItemCache6->DnsCache.IpAddress); | |
| } | |
| FreePool (ItemCache6); | |
| } | |
| while (!IsListEmpty (&mDriverData->Dns6ServerList)) { | |
| Entry = NetListRemoveHead (&mDriverData->Dns6ServerList); | |
| ItemServerIp6 = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink); | |
| FreePool (ItemServerIp6); | |
| } | |
| FreePool (mDriverData); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This is the declaration of an EFI image entry point. This entry point is | |
| the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including | |
| both device drivers and bus drivers. | |
| @param ImageHandle The firmware allocated handle for the UEFI image. | |
| @param SystemTable A pointer to the EFI System Table. | |
| @retval EFI_SUCCESS The operation completed successfully. | |
| @retval Others An unexpected error occurred. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DnsDriverEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| // | |
| // Install the Dns4 Driver Binding Protocol. | |
| // | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gDns4DriverBinding, | |
| ImageHandle, | |
| &gDnsComponentName, | |
| &gDnsComponentName2 | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Install the Dns6 Driver Binding Protocol. | |
| // | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gDns6DriverBinding, | |
| NULL, | |
| &gDnsComponentName, | |
| &gDnsComponentName2 | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error1; | |
| } | |
| // | |
| // Create the driver data structures. | |
| // | |
| mDriverData = AllocateZeroPool (sizeof (DNS_DRIVER_DATA)); | |
| if (mDriverData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Error2; | |
| } | |
| // | |
| // Create the timer event to update DNS cache list. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL | EVT_TIMER, | |
| TPL_CALLBACK, | |
| DnsOnTimerUpdate, | |
| NULL, | |
| &mDriverData->Timer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error3; | |
| } | |
| Status = gBS->SetTimer (mDriverData->Timer, TimerPeriodic, TICKS_PER_SECOND); | |
| if (EFI_ERROR (Status)) { | |
| goto Error4; | |
| } | |
| InitializeListHead (&mDriverData->Dns4CacheList); | |
| InitializeListHead (&mDriverData->Dns4ServerList); | |
| InitializeListHead (&mDriverData->Dns6CacheList); | |
| InitializeListHead (&mDriverData->Dns6ServerList); | |
| return Status; | |
| Error4: | |
| gBS->CloseEvent (mDriverData->Timer); | |
| Error3: | |
| FreePool (mDriverData); | |
| Error2: | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| gDns6DriverBinding.DriverBindingHandle, | |
| &gEfiDriverBindingProtocolGuid, | |
| &gDns6DriverBinding, | |
| &gEfiComponentName2ProtocolGuid, | |
| &gDnsComponentName2, | |
| &gEfiComponentNameProtocolGuid, | |
| &gDnsComponentName, | |
| NULL | |
| ); | |
| Error1: | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| ImageHandle, | |
| &gEfiDriverBindingProtocolGuid, | |
| &gDns4DriverBinding, | |
| &gEfiComponentName2ProtocolGuid, | |
| &gDnsComponentName2, | |
| &gEfiComponentNameProtocolGuid, | |
| &gDnsComponentName, | |
| NULL | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Tests to see if this driver supports a given controller. If a child device is provided, | |
| it further tests to see if this driver supports creating a handle for the specified child device. | |
| This function checks to see if the driver specified by This supports the device specified by | |
| ControllerHandle. Drivers will typically use the device path attached to | |
| ControllerHandle and/or the services from the bus I/O abstraction attached to | |
| ControllerHandle to determine if the driver supports ControllerHandle. This function | |
| may be called many times during platform initialization. In order to reduce boot times, the tests | |
| performed by this function must be very small, and take as little time as possible to execute. This | |
| function must not change the state of any hardware devices, and this function must be aware that the | |
| device specified by ControllerHandle may already be managed by the same driver or a | |
| different driver. This function must match its calls to AllocatePages() with FreePages(), | |
| AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). | |
| Because ControllerHandle may have been previously started by the same driver, if a protocol is | |
| already in the opened state, then it must not be closed with CloseProtocol(). This is required | |
| to guarantee the state of ControllerHandle is not modified by this function. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle The handle of the controller to test. This handle | |
| must support a protocol interface that supplies | |
| an I/O abstraction to the driver. | |
| @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This | |
| parameter is ignored by device drivers, and is optional for bus | |
| drivers. For bus drivers, if this parameter is not NULL, then | |
| the bus driver must determine if the bus controller specified | |
| by ControllerHandle and the child controller specified | |
| by RemainingDevicePath are both supported by this | |
| bus driver. | |
| @retval EFI_SUCCESS The device specified by ControllerHandle and | |
| RemainingDevicePath is supported by the driver specified by This. | |
| @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and | |
| RemainingDevicePath is already being managed by the driver | |
| specified by This. | |
| @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and | |
| RemainingDevicePath is already being managed by a different | |
| driver or an application that requires exclusive access. | |
| Currently not implemented. | |
| @retval EFI_UNSUPPORTED The device specified by ControllerHandle and | |
| RemainingDevicePath is not supported by the driver specified by This. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns4DriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Test for the Dns4ServiceBinding Protocol. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiDns4ServiceBindingProtocolGuid, | |
| NULL, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| // | |
| // Test for the Udp4ServiceBinding Protocol. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUdp4ServiceBindingProtocolGuid, | |
| NULL, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Starts a device controller or a bus controller. | |
| The Start() function is designed to be invoked from the EFI boot service ConnectController(). | |
| As a result, much of the error checking on the parameters to Start() has been moved into this | |
| common boot service. It is legal to call Start() from other locations, | |
| but the following calling restrictions must be followed, or the system behavior will not be deterministic. | |
| 1. ControllerHandle must be a valid EFI_HANDLE. | |
| 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned | |
| EFI_DEVICE_PATH_PROTOCOL. | |
| 3. Prior to calling Start(), the Supported() function for the driver specified by This must | |
| have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle The handle of the controller to start. This handle | |
| must support a protocol interface that supplies | |
| an I/O abstraction to the driver. | |
| @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This | |
| parameter is ignored by device drivers, and is optional for bus | |
| drivers. For a bus driver, if this parameter is NULL, then handles | |
| for all the children of Controller are created by this driver. | |
| If this parameter is not NULL and the first Device Path Node is | |
| not the End of Device Path Node, then only the handle for the | |
| child device specified by the first Device Path Node of | |
| RemainingDevicePath is created by this driver. | |
| If the first Device Path Node of RemainingDevicePath is | |
| the End of Device Path Node, no child handle is created by this | |
| driver. | |
| @retval EFI_SUCCESS The device was started. | |
| @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. | |
| @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. | |
| @retval Others The driver failded to start the device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns4DriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| EFI_STATUS Status; | |
| Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4, &DnsSb); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT (DnsSb != NULL); | |
| Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Install the Dns4ServiceBinding Protocol onto ControllerHandle. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &ControllerHandle, | |
| &gEfiDns4ServiceBindingProtocolGuid, | |
| &DnsSb->ServiceBinding, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| DnsDestroyService (DnsSb); | |
| return Status; | |
| } | |
| /** | |
| Stops a device controller or a bus controller. | |
| The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). | |
| As a result, much of the error checking on the parameters to Stop() has been moved | |
| into this common boot service. It is legal to call Stop() from other locations, | |
| but the following calling restrictions must be followed, or the system behavior will not be deterministic. | |
| 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this | |
| same driver's Start() function. | |
| 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid | |
| EFI_HANDLE. In addition, all of these handles must have been created in this driver's | |
| Start() function, and the Start() function must have called OpenProtocol() on | |
| ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle A handle to the device being stopped. The handle must | |
| support a bus specific I/O protocol for the driver | |
| to use to stop the device. | |
| @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. | |
| @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL | |
| if NumberOfChildren is 0. | |
| @retval EFI_SUCCESS The device was stopped. | |
| @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns4DriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer OPTIONAL | |
| ) | |
| { | |
| EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; | |
| DNS_SERVICE *DnsSb; | |
| EFI_HANDLE NicHandle; | |
| EFI_STATUS Status; | |
| LIST_ENTRY *List; | |
| DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; | |
| // | |
| // DNS driver opens UDP child, So, Controller is a UDP | |
| // child handle. Locate the Nic handle first. Then get the | |
| // DNS private data back. | |
| // | |
| NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid); | |
| if (NicHandle == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| NicHandle, | |
| &gEfiDns4ServiceBindingProtocolGuid, | |
| (VOID **) &ServiceBinding, | |
| This->DriverBindingHandle, | |
| NicHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding); | |
| if (!IsListEmpty (&DnsSb->Dns4ChildrenList)) { | |
| // | |
| // Destroy the Dns child instance in ChildHandleBuffer. | |
| // | |
| List = &DnsSb->Dns4ChildrenList; | |
| Context.ServiceBinding = ServiceBinding; | |
| Context.NumberOfChildren = NumberOfChildren; | |
| Context.ChildHandleBuffer = ChildHandleBuffer; | |
| Status = NetDestroyLinkList ( | |
| List, | |
| DnsDestroyChildEntryInHandleBuffer, | |
| &Context, | |
| NULL | |
| ); | |
| } | |
| if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns4ChildrenList)) { | |
| gBS->UninstallProtocolInterface ( | |
| NicHandle, | |
| &gEfiDns4ServiceBindingProtocolGuid, | |
| ServiceBinding | |
| ); | |
| DnsDestroyService (DnsSb); | |
| if (gDnsControllerNameTable != NULL) { | |
| FreeUnicodeStringTable (gDnsControllerNameTable); | |
| gDnsControllerNameTable = NULL; | |
| } | |
| Status = EFI_SUCCESS; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Tests to see if this driver supports a given controller. If a child device is provided, | |
| it further tests to see if this driver supports creating a handle for the specified child device. | |
| This function checks to see if the driver specified by This supports the device specified by | |
| ControllerHandle. Drivers will typically use the device path attached to | |
| ControllerHandle and/or the services from the bus I/O abstraction attached to | |
| ControllerHandle to determine if the driver supports ControllerHandle. This function | |
| may be called many times during platform initialization. In order to reduce boot times, the tests | |
| performed by this function must be very small, and take as little time as possible to execute. This | |
| function must not change the state of any hardware devices, and this function must be aware that the | |
| device specified by ControllerHandle may already be managed by the same driver or a | |
| different driver. This function must match its calls to AllocatePages() with FreePages(), | |
| AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). | |
| Because ControllerHandle may have been previously started by the same driver, if a protocol is | |
| already in the opened state, then it must not be closed with CloseProtocol(). This is required | |
| to guarantee the state of ControllerHandle is not modified by this function. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle The handle of the controller to test. This handle | |
| must support a protocol interface that supplies | |
| an I/O abstraction to the driver. | |
| @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This | |
| parameter is ignored by device drivers, and is optional for bus | |
| drivers. For bus drivers, if this parameter is not NULL, then | |
| the bus driver must determine if the bus controller specified | |
| by ControllerHandle and the child controller specified | |
| by RemainingDevicePath are both supported by this | |
| bus driver. | |
| @retval EFI_SUCCESS The device specified by ControllerHandle and | |
| RemainingDevicePath is supported by the driver specified by This. | |
| @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and | |
| RemainingDevicePath is already being managed by the driver | |
| specified by This. | |
| @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and | |
| RemainingDevicePath is already being managed by a different | |
| driver or an application that requires exclusive access. | |
| Currently not implemented. | |
| @retval EFI_UNSUPPORTED The device specified by ControllerHandle and | |
| RemainingDevicePath is not supported by the driver specified by This. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns6DriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Test for the Dns6ServiceBinding Protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiDns6ServiceBindingProtocolGuid, | |
| NULL, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| // | |
| // Test for the Udp6ServiceBinding Protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUdp6ServiceBindingProtocolGuid, | |
| NULL, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Starts a device controller or a bus controller. | |
| The Start() function is designed to be invoked from the EFI boot service ConnectController(). | |
| As a result, much of the error checking on the parameters to Start() has been moved into this | |
| common boot service. It is legal to call Start() from other locations, | |
| but the following calling restrictions must be followed, or the system behavior will not be deterministic. | |
| 1. ControllerHandle must be a valid EFI_HANDLE. | |
| 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned | |
| EFI_DEVICE_PATH_PROTOCOL. | |
| 3. Prior to calling Start(), the Supported() function for the driver specified by This must | |
| have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle The handle of the controller to start. This handle | |
| must support a protocol interface that supplies | |
| an I/O abstraction to the driver. | |
| @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This | |
| parameter is ignored by device drivers, and is optional for bus | |
| drivers. For a bus driver, if this parameter is NULL, then handles | |
| for all the children of Controller are created by this driver. | |
| If this parameter is not NULL and the first Device Path Node is | |
| not the End of Device Path Node, then only the handle for the | |
| child device specified by the first Device Path Node of | |
| RemainingDevicePath is created by this driver. | |
| If the first Device Path Node of RemainingDevicePath is | |
| the End of Device Path Node, no child handle is created by this | |
| driver. | |
| @retval EFI_SUCCESS The device was started. | |
| @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. | |
| @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. | |
| @retval Others The driver failded to start the device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns6DriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| EFI_STATUS Status; | |
| Status = DnsCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6, &DnsSb); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT (DnsSb != NULL); | |
| Status = gBS->SetTimer (DnsSb->Timer, TimerPeriodic, TICKS_PER_SECOND); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Install the Dns6ServiceBinding Protocol onto ControllerHandle | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &ControllerHandle, | |
| &gEfiDns6ServiceBindingProtocolGuid, | |
| &DnsSb->ServiceBinding, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| DnsDestroyService (DnsSb); | |
| return Status; | |
| } | |
| /** | |
| Stops a device controller or a bus controller. | |
| The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). | |
| As a result, much of the error checking on the parameters to Stop() has been moved | |
| into this common boot service. It is legal to call Stop() from other locations, | |
| but the following calling restrictions must be followed, or the system behavior will not be deterministic. | |
| 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this | |
| same driver's Start() function. | |
| 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid | |
| EFI_HANDLE. In addition, all of these handles must have been created in this driver's | |
| Start() function, and the Start() function must have called OpenProtocol() on | |
| ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. | |
| @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. | |
| @param[in] ControllerHandle A handle to the device being stopped. The handle must | |
| support a bus specific I/O protocol for the driver | |
| to use to stop the device. | |
| @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. | |
| @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL | |
| if NumberOfChildren is 0. | |
| @retval EFI_SUCCESS The device was stopped. | |
| @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns6DriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer OPTIONAL | |
| ) | |
| { | |
| EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; | |
| DNS_SERVICE *DnsSb; | |
| EFI_HANDLE NicHandle; | |
| EFI_STATUS Status; | |
| LIST_ENTRY *List; | |
| DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; | |
| // | |
| // DNS driver opens UDP child, So, Controller is a UDP | |
| // child handle. Locate the Nic handle first. Then get the | |
| // DNS private data back. | |
| // | |
| NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid); | |
| if (NicHandle == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| NicHandle, | |
| &gEfiDns6ServiceBindingProtocolGuid, | |
| (VOID **) &ServiceBinding, | |
| This->DriverBindingHandle, | |
| NicHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| DnsSb = DNS_SERVICE_FROM_THIS (ServiceBinding); | |
| if (!IsListEmpty (&DnsSb->Dns6ChildrenList)) { | |
| // | |
| // Destroy the Dns child instance in ChildHandleBuffer. | |
| // | |
| List = &DnsSb->Dns6ChildrenList; | |
| Context.ServiceBinding = ServiceBinding; | |
| Context.NumberOfChildren = NumberOfChildren; | |
| Context.ChildHandleBuffer = ChildHandleBuffer; | |
| Status = NetDestroyLinkList ( | |
| List, | |
| DnsDestroyChildEntryInHandleBuffer, | |
| &Context, | |
| NULL | |
| ); | |
| } | |
| if (NumberOfChildren == 0 && IsListEmpty (&DnsSb->Dns6ChildrenList)) { | |
| gBS->UninstallProtocolInterface ( | |
| NicHandle, | |
| &gEfiDns6ServiceBindingProtocolGuid, | |
| ServiceBinding | |
| ); | |
| DnsDestroyService (DnsSb); | |
| if (gDnsControllerNameTable != NULL) { | |
| FreeUnicodeStringTable (gDnsControllerNameTable); | |
| gDnsControllerNameTable = NULL; | |
| } | |
| Status = EFI_SUCCESS; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Creates a child handle and installs a protocol. | |
| The CreateChild() function installs a protocol on ChildHandle. | |
| If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. | |
| If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. | |
| @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
| @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, | |
| then a new handle is created. If it is a pointer to an existing UEFI handle, | |
| then the protocol is added to the existing UEFI handle. | |
| @retval EFI_SUCCES The protocol was added to ChildHandle. | |
| @retval EFI_INVALID_PARAMETER ChildHandle is NULL. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create | |
| the child | |
| @retval other The child handle was not created | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns4ServiceBindingCreateChild ( | |
| IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE *ChildHandle | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| DNS_INSTANCE *Instance; | |
| EFI_STATUS Status; | |
| EFI_TPL OldTpl; | |
| VOID *Udp4; | |
| if ((This == NULL) || (ChildHandle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| DnsSb = DNS_SERVICE_FROM_THIS (This); | |
| Status = DnsCreateInstance (DnsSb, &Instance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT (Instance != NULL); | |
| // | |
| // Install the DNS protocol onto ChildHandle | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| ChildHandle, | |
| &gEfiDns4ProtocolGuid, | |
| &Instance->Dns4, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Instance->ChildHandle = *ChildHandle; | |
| // | |
| // Open the Udp4 protocol BY_CHILD. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp4ProtocolGuid, | |
| (VOID **) &Udp4, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| Instance->ChildHandle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| Instance->ChildHandle, | |
| &gEfiDns4ProtocolGuid, | |
| &Instance->Dns4, | |
| NULL | |
| ); | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Open the Udp4 protocol by child. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Instance->UdpIo->UdpHandle, | |
| &gEfiUdp4ProtocolGuid, | |
| (VOID **) &Udp4, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| Instance->ChildHandle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Close the Udp4 protocol. | |
| // | |
| gBS->CloseProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp4ProtocolGuid, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| Instance->ChildHandle, | |
| &gEfiDns4ProtocolGuid, | |
| &Instance->Dns4, | |
| NULL | |
| ); | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Add it to the parent's child list. | |
| // | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| InsertTailList (&DnsSb->Dns4ChildrenList, &Instance->Link); | |
| DnsSb->Dns4ChildrenNum++; | |
| gBS->RestoreTPL (OldTpl); | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| DnsDestroyInstance (Instance); | |
| return Status; | |
| } | |
| /** | |
| Destroys a child handle with a protocol installed on it. | |
| The DestroyChild() function does the opposite of CreateChild(). It removes a protocol | |
| that was installed by CreateChild() from ChildHandle. If the removed protocol is the | |
| last protocol on ChildHandle, then ChildHandle is destroyed. | |
| @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
| @param[in] ChildHandle Handle of the child to destroy | |
| @retval EFI_SUCCES The protocol was removed from ChildHandle. | |
| @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. | |
| @retval EFI_INVALID_PARAMETER Child handle is NULL. | |
| @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle | |
| because its services are being used. | |
| @retval other The child handle was not destroyed | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns4ServiceBindingDestroyChild ( | |
| IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ChildHandle | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| DNS_INSTANCE *Instance; | |
| EFI_DNS4_PROTOCOL *Dns4; | |
| EFI_STATUS Status; | |
| EFI_TPL OldTpl; | |
| if ((This == NULL) || (ChildHandle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Retrieve the private context data structures | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ChildHandle, | |
| &gEfiDns4ProtocolGuid, | |
| (VOID **) &Dns4, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| ChildHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (Dns4); | |
| DnsSb = DNS_SERVICE_FROM_THIS (This); | |
| if (Instance->Service != DnsSb) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Instance->InDestroy) { | |
| return EFI_SUCCESS; | |
| } | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| Instance->InDestroy = TRUE; | |
| // | |
| // Close the Udp4 protocol. | |
| // | |
| gBS->CloseProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp4ProtocolGuid, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| Instance->UdpIo->UdpHandle, | |
| &gEfiUdp4ProtocolGuid, | |
| gDns4DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->RestoreTPL (OldTpl); | |
| // | |
| // Uninstall the DNS protocol first to enable a top down destruction. | |
| // | |
| Status = gBS->UninstallProtocolInterface ( | |
| ChildHandle, | |
| &gEfiDns4ProtocolGuid, | |
| Dns4 | |
| ); | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| if (EFI_ERROR (Status)) { | |
| Instance->InDestroy = FALSE; | |
| gBS->RestoreTPL (OldTpl); | |
| return Status; | |
| } | |
| RemoveEntryList (&Instance->Link); | |
| DnsSb->Dns4ChildrenNum--; | |
| gBS->RestoreTPL (OldTpl); | |
| DnsDestroyInstance (Instance); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Creates a child handle and installs a protocol. | |
| The CreateChild() function installs a protocol on ChildHandle. | |
| If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. | |
| If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. | |
| @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
| @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, | |
| then a new handle is created. If it is a pointer to an existing UEFI handle, | |
| then the protocol is added to the existing UEFI handle. | |
| @retval EFI_SUCCES The protocol was added to ChildHandle. | |
| @retval EFI_INVALID_PARAMETER ChildHandle is NULL. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create | |
| the child | |
| @retval other The child handle was not created | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns6ServiceBindingCreateChild ( | |
| IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE *ChildHandle | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| DNS_INSTANCE *Instance; | |
| EFI_STATUS Status; | |
| EFI_TPL OldTpl; | |
| VOID *Udp6; | |
| if ((This == NULL) || (ChildHandle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| DnsSb = DNS_SERVICE_FROM_THIS (This); | |
| Status = DnsCreateInstance (DnsSb, &Instance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT (Instance != NULL); | |
| // | |
| // Install the DNS protocol onto ChildHandle | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| ChildHandle, | |
| &gEfiDns6ProtocolGuid, | |
| &Instance->Dns6, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Instance->ChildHandle = *ChildHandle; | |
| // | |
| // Open the Udp6 protocol BY_CHILD. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp6ProtocolGuid, | |
| (VOID **) &Udp6, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| Instance->ChildHandle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| Instance->ChildHandle, | |
| &gEfiDns6ProtocolGuid, | |
| &Instance->Dns6, | |
| NULL | |
| ); | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Open the Udp6 protocol by child. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Instance->UdpIo->UdpHandle, | |
| &gEfiUdp6ProtocolGuid, | |
| (VOID **) &Udp6, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| Instance->ChildHandle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Close the Udp6 protocol. | |
| // | |
| gBS->CloseProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp6ProtocolGuid, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| Instance->ChildHandle, | |
| &gEfiDns6ProtocolGuid, | |
| &Instance->Dns6, | |
| NULL | |
| ); | |
| goto ON_ERROR; | |
| } | |
| // | |
| // Add it to the parent's child list. | |
| // | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| InsertTailList (&DnsSb->Dns6ChildrenList, &Instance->Link); | |
| DnsSb->Dns6ChildrenNum++; | |
| gBS->RestoreTPL (OldTpl); | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| DnsDestroyInstance (Instance); | |
| return Status; | |
| } | |
| /** | |
| Destroys a child handle with a protocol installed on it. | |
| The DestroyChild() function does the opposite of CreateChild(). It removes a protocol | |
| that was installed by CreateChild() from ChildHandle. If the removed protocol is the | |
| last protocol on ChildHandle, then ChildHandle is destroyed. | |
| @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
| @param[in] ChildHandle Handle of the child to destroy | |
| @retval EFI_SUCCES The protocol was removed from ChildHandle. | |
| @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. | |
| @retval EFI_INVALID_PARAMETER Child handle is NULL. | |
| @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle | |
| because its services are being used. | |
| @retval other The child handle was not destroyed | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Dns6ServiceBindingDestroyChild ( | |
| IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ChildHandle | |
| ) | |
| { | |
| DNS_SERVICE *DnsSb; | |
| DNS_INSTANCE *Instance; | |
| EFI_DNS6_PROTOCOL *Dns6; | |
| EFI_STATUS Status; | |
| EFI_TPL OldTpl; | |
| if ((This == NULL) || (ChildHandle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Retrieve the private context data structures | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ChildHandle, | |
| &gEfiDns6ProtocolGuid, | |
| (VOID **) &Dns6, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| ChildHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (Dns6); | |
| DnsSb = DNS_SERVICE_FROM_THIS (This); | |
| if (Instance->Service != DnsSb) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Instance->InDestroy) { | |
| return EFI_SUCCESS; | |
| } | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| Instance->InDestroy = TRUE; | |
| // | |
| // Close the Udp6 protocol. | |
| // | |
| gBS->CloseProtocol ( | |
| DnsSb->ConnectUdp->UdpHandle, | |
| &gEfiUdp6ProtocolGuid, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| Instance->UdpIo->UdpHandle, | |
| &gEfiUdp6ProtocolGuid, | |
| gDns6DriverBinding.DriverBindingHandle, | |
| ChildHandle | |
| ); | |
| gBS->RestoreTPL (OldTpl); | |
| // | |
| // Uninstall the DNS protocol first to enable a top down destruction. | |
| // | |
| Status = gBS->UninstallProtocolInterface ( | |
| ChildHandle, | |
| &gEfiDns6ProtocolGuid, | |
| Dns6 | |
| ); | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| if (EFI_ERROR (Status)) { | |
| Instance->InDestroy = FALSE; | |
| gBS->RestoreTPL (OldTpl); | |
| return Status; | |
| } | |
| RemoveEntryList (&Instance->Link); | |
| DnsSb->Dns6ChildrenNum--; | |
| gBS->RestoreTPL (OldTpl); | |
| DnsDestroyInstance (Instance); | |
| return EFI_SUCCESS; | |
| } |