From 99c048ef4aca44589d519946ee6a6c890ad9123b Mon Sep 17 00:00:00 2001 From: jiaxinwu Date: Tue, 7 Jul 2015 08:22:03 +0000 Subject: [PATCH 1/1] NetworkPkg: Add DNS feature support over IPv4 and IPv6. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: jiaxinwu Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17854 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/DnsDxe/ComponentName.c | 443 +++++++ NetworkPkg/DnsDxe/DnsDhcp.c | 762 ++++++++++++ NetworkPkg/DnsDxe/DnsDhcp.h | 145 +++ NetworkPkg/DnsDxe/DnsDriver.c | 1554 ++++++++++++++++++++++++ NetworkPkg/DnsDxe/DnsDriver.h | 606 ++++++++++ NetworkPkg/DnsDxe/DnsDxe.inf | 76 ++ NetworkPkg/DnsDxe/DnsImpl.c | 1875 +++++++++++++++++++++++++++++ NetworkPkg/DnsDxe/DnsImpl.h | 1139 ++++++++++++++++++ NetworkPkg/DnsDxe/DnsProtocol.c | 1344 +++++++++++++++++++++ 9 files changed, 7944 insertions(+) create mode 100644 NetworkPkg/DnsDxe/ComponentName.c create mode 100644 NetworkPkg/DnsDxe/DnsDhcp.c create mode 100644 NetworkPkg/DnsDxe/DnsDhcp.h create mode 100644 NetworkPkg/DnsDxe/DnsDriver.c create mode 100644 NetworkPkg/DnsDxe/DnsDriver.h create mode 100644 NetworkPkg/DnsDxe/DnsDxe.inf create mode 100644 NetworkPkg/DnsDxe/DnsImpl.c create mode 100644 NetworkPkg/DnsDxe/DnsImpl.h create mode 100644 NetworkPkg/DnsDxe/DnsProtocol.c diff --git a/NetworkPkg/DnsDxe/ComponentName.c b/NetworkPkg/DnsDxe/ComponentName.c new file mode 100644 index 0000000000..d95ed92d8a --- /dev/null +++ b/NetworkPkg/DnsDxe/ComponentName.c @@ -0,0 +1,443 @@ +/** @file +Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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 Component Name Functions +// +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DnsComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DnsComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +/// +/// Component Name Protocol instance +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME_PROTOCOL gDnsComponentName = { + DnsComponentNameGetDriverName, + DnsComponentNameGetControllerName, + "eng" +}; + +/// +/// Component Name 2 Protocol instance +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME2_PROTOCOL gDnsComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DnsComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DnsComponentNameGetControllerName, + "en" +}; + +/// +/// Table of driver names +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_UNICODE_STRING_TABLE mDnsDriverNameTable[] = { + { "eng;en", (CHAR16 *)L"DNS Network Service Driver" }, + { NULL, NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gDnsControllerNameTable = NULL; + +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DnsComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mDnsDriverNameTable, + DriverName, + (BOOLEAN)(This == &gDnsComponentName) + ); +} + +/** + Update the component name for the Dns4 child handle. + + @param Dns4 A pointer to the EFI_DNS4_PROTOCOL. + + + @retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully. + @retval EFI_INVALID_PARAMETER The input parameter is invalid. + +**/ +EFI_STATUS +UpdateDns4Name ( + EFI_DNS4_PROTOCOL *Dns4 + ) +{ + EFI_STATUS Status; + CHAR16 HandleName[80]; + EFI_DNS4_MODE_DATA ModeData; + + if (Dns4 == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format the child name into the string buffer as: + // DNSv4 (StationIp=?, LocalPort=?) + // + Status = Dns4->GetModeData (Dns4, &ModeData); + if (EFI_ERROR (Status)) { + return Status; + } + + UnicodeSPrint ( + HandleName, + sizeof (HandleName), + L"DNSv4 (StationIp=%d.%d.%d.%d, LocalPort=%d)", + ModeData.DnsConfigData.StationIp.Addr[0], + ModeData.DnsConfigData.StationIp.Addr[1], + ModeData.DnsConfigData.StationIp.Addr[2], + ModeData.DnsConfigData.StationIp.Addr[3], + ModeData.DnsConfigData.LocalPort + ); + + if (gDnsControllerNameTable != NULL) { + FreeUnicodeStringTable (gDnsControllerNameTable); + gDnsControllerNameTable = NULL; + } + + Status = AddUnicodeString2 ( + "eng", + gDnsComponentName.SupportedLanguages, + &gDnsControllerNameTable, + HandleName, + TRUE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return AddUnicodeString2 ( + "en", + gDnsComponentName2.SupportedLanguages, + &gDnsControllerNameTable, + HandleName, + FALSE + ); +} + +/** + Update the component name for the Dns6 child handle. + + @param Dns6 A pointer to the EFI_DNS6_PROTOCOL. + + + @retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully. + @retval EFI_INVALID_PARAMETER The input parameter is invalid. + +**/ +EFI_STATUS +UpdateDns6Name ( + EFI_DNS6_PROTOCOL *Dns6 + ) +{ + EFI_STATUS Status; + CHAR16 HandleName[128]; + EFI_DNS6_MODE_DATA ModeData; + CHAR16 Address[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + + if (Dns6 == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format the child name into the string buffer as: + // DNSv6 (StationIp=?, LocalPort=?) + // + Status = Dns6->GetModeData (Dns6, &ModeData); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = NetLibIp6ToStr (&ModeData.DnsConfigData.StationIp, Address, sizeof (Address)); + if (EFI_ERROR (Status)) { + return Status; + } + UnicodeSPrint ( + HandleName, + sizeof (HandleName), + L"DNSv6 (StationIp=%s, LocalPort=%d)", + Address, + ModeData.DnsConfigData.LocalPort + ); + + if (gDnsControllerNameTable != NULL) { + FreeUnicodeStringTable (gDnsControllerNameTable); + gDnsControllerNameTable = NULL; + } + + Status = AddUnicodeString2 ( + "eng", + gDnsComponentName.SupportedLanguages, + &gDnsControllerNameTable, + HandleName, + TRUE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return AddUnicodeString2 ( + "en", + gDnsComponentName2.SupportedLanguages, + &gDnsControllerNameTable, + HandleName, + FALSE + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DnsComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_DNS4_PROTOCOL *Dns4; + EFI_DNS6_PROTOCOL *Dns6; + + // + // ChildHandle must be NULL for a Device Driver + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver produced ChildHandle + // + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiUdp6ProtocolGuid + ); + if (!EFI_ERROR (Status)) { + // + // Retrieve an instance of a produced protocol from ChildHandle + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiDns6ProtocolGuid, + (VOID **)&Dns6, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update the component name for this child handle. + // + Status = UpdateDns6Name (Dns6); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Make sure this driver produced ChildHandle + // + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiUdp4ProtocolGuid + ); + if (!EFI_ERROR (Status)) { + // + // Retrieve an instance of a produced protocol from ChildHandle + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiDns4ProtocolGuid, + (VOID **)&Dns4, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update the component name for this child handle. + // + Status = UpdateDns4Name (Dns4); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + gDnsControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gDnsComponentName) + ); +} diff --git a/NetworkPkg/DnsDxe/DnsDhcp.c b/NetworkPkg/DnsDxe/DnsDhcp.c new file mode 100644 index 0000000000..4607f7b633 --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsDhcp.c @@ -0,0 +1,762 @@ +/** @file +Functions implementation related with DHCPv4/v6 for DNS driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +**/ + +#include "DnsImpl.h" + +/** + This function initialize the DHCP4 message instance. + + This function will pad each item of dhcp4 message packet. + + @param Seed Pointer to the message instance of the DHCP4 packet. + @param InterfaceInfo Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance. + +**/ +VOID +DnsInitSeedPacket ( + OUT EFI_DHCP4_PACKET *Seed, + IN EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo + ) +{ + EFI_DHCP4_HEADER *Header; + + // + // Get IfType and HwAddressSize from SNP mode data. + // + Seed->Size = sizeof (EFI_DHCP4_PACKET); + Seed->Length = sizeof (Seed->Dhcp4); + Header = &Seed->Dhcp4.Header; + ZeroMem (Header, sizeof (EFI_DHCP4_HEADER)); + Header->OpCode = DHCP4_OPCODE_REQUEST; + Header->HwType = InterfaceInfo->IfType; + Header->HwAddrLen = (UINT8) InterfaceInfo->HwAddressSize; + CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen); + + Seed->Dhcp4.Magik = DHCP4_MAGIC; + Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP; +} + +/** + The common notify function. + + @param[in] Event The event signaled. + @param[in] Context The context. + +**/ +VOID +EFIAPI +DhcpCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if ((Event == NULL) || (Context == NULL)) { + return ; + } + + *((BOOLEAN *) Context) = TRUE; +} + +/** + Parse the ACK to get required information + + @param Dhcp4 The DHCP4 protocol. + @param Packet Packet waiting for parse. + @param DnsServerInfor The required Dns4 server information. + + @retval EFI_SUCCESS The DNS information is got from the DHCP ACK. + @retval EFI_NO_MAPPING DHCP failed to acquire address and other information. + @retval EFI_DEVICE_ERROR Other errors as indicated. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + +**/ +EFI_STATUS +ParseDhcp4Ack ( + IN EFI_DHCP4_PROTOCOL *Dhcp4, + IN EFI_DHCP4_PACKET *Packet, + IN DNS4_SERVER_INFOR *DnsServerInfor + ) +{ + EFI_STATUS Status; + UINT32 OptionCount; + EFI_DHCP4_PACKET_OPTION **OptionList; + UINT32 ServerCount; + EFI_IPv4_ADDRESS *ServerList; + UINT32 Index; + UINT32 Count; + + ServerCount = 0; + ServerList = NULL; + + OptionCount = 0; + OptionList = NULL; + + Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList); + if (Status != EFI_BUFFER_TOO_SMALL) { + return EFI_DEVICE_ERROR; + } + + OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *)); + if (OptionList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList); + if (EFI_ERROR (Status)) { + gBS->FreePool (OptionList); + return EFI_DEVICE_ERROR; + } + + Status = EFI_NOT_FOUND; + + for (Index = 0; Index < OptionCount; Index++) { + // + // Get DNS server addresses + // + if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) { + + if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) { + Status = EFI_DEVICE_ERROR; + break; + } + + ServerCount = OptionList[Index]->Length/4; + ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS)); + if (ServerList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for(Count=0; Count < ServerCount; Count++){ + CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS)); + } + + *(DnsServerInfor->ServerCount) = ServerCount; + DnsServerInfor->ServerList = ServerList; + + Status = EFI_SUCCESS; + } + } + + gBS->FreePool (OptionList); + + return Status; +} + +/** + EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol + instance to intercept events that occurs in the DHCPv6 Information Request + exchange process. + + @param This Pointer to the EFI_DHCP6_PROTOCOL instance that + is used to configure this callback function. + @param Context Pointer to the context that is initialized in + the EFI_DHCP6_PROTOCOL.InfoRequest(). + @param Packet Pointer to Reply packet that has been received. + The EFI DHCPv6 Protocol instance is responsible + for freeing the buffer. + + @retval EFI_SUCCESS The DNS information is got from the DHCP ACK. + @retval EFI_DEVICE_ERROR Other errors as indicated. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ParseDhcp6Ack ( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_PACKET *Packet + ) +{ + EFI_STATUS Status; + UINT32 OptionCount; + EFI_DHCP6_PACKET_OPTION **OptionList; + DNS6_SERVER_INFOR *DnsServerInfor; + UINT32 ServerCount; + EFI_IPv6_ADDRESS *ServerList; + UINT32 Index; + UINT32 Count; + + OptionCount = 0; + ServerCount = 0; + ServerList = NULL; + + Status = This->Parse (This, Packet, &OptionCount, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + return EFI_DEVICE_ERROR; + } + + OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *)); + if (OptionList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = This->Parse (This, Packet, &OptionCount, OptionList); + if (EFI_ERROR (Status)) { + gBS->FreePool (OptionList); + return EFI_DEVICE_ERROR; + } + + DnsServerInfor = (DNS6_SERVER_INFOR *) Context; + + for (Index = 0; Index < OptionCount; Index++) { + OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode); + OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen); + + // + // Get DNS server addresses from this reply packet. + // + if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) { + + if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) { + Status = EFI_DEVICE_ERROR; + gBS->FreePool (OptionList); + return Status; + } + + ServerCount = OptionList[Index]->OpLen/16; + ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS)); + if (ServerList == NULL) { + gBS->FreePool (OptionList); + return EFI_OUT_OF_RESOURCES; + } + + for(Count=0; Count < ServerCount; Count++){ + CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS)); + } + + *(DnsServerInfor->ServerCount) = ServerCount; + DnsServerInfor->ServerList = ServerList; + } + } + + gBS->FreePool (OptionList); + + return Status; + +} + +/** + Parse the DHCP ACK to get Dns4 server information. + + @param Instance The DNS instance. + @param DnsServerCount Retrieved Dns4 server Ip count. + @param DnsServerList Retrieved Dns4 server Ip list. + + @retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_NO_MEDIA There was a media error. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +GetDns4ServerFromDhcp4 ( + IN DNS_INSTANCE *Instance, + OUT UINT32 *DnsServerCount, + OUT EFI_IPv4_ADDRESS **DnsServerList + ) +{ + EFI_STATUS Status; + EFI_HANDLE Image; + EFI_HANDLE Controller; + BOOLEAN MediaPresent; + EFI_HANDLE MnpChildHandle; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData; + EFI_HANDLE Dhcp4Handle; + EFI_DHCP4_PROTOCOL *Dhcp4; + EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; + UINTN DataSize; + VOID *Data; + EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo; + EFI_DHCP4_PACKET SeedPacket; + EFI_DHCP4_PACKET_OPTION *ParaList[2]; + DNS4_SERVER_INFOR DnsServerInfor; + + EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; + BOOLEAN IsDone; + UINTN Index; + + Image = Instance->Service->ImageHandle; + Controller = Instance->Service->ControllerHandle; + + MnpChildHandle = NULL; + Mnp = NULL; + + Dhcp4Handle = NULL; + Dhcp4 = NULL; + + Ip4Config2 = NULL; + DataSize = 0; + Data = NULL; + InterfaceInfo = NULL; + + ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA)); + + ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR)); + + ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN)); + + DnsServerInfor.ServerCount = DnsServerCount; + + IsDone = FALSE; + + // + // Check media. + // + MediaPresent = TRUE; + NetLibDetectMedia (Controller, &MediaPresent); + if (!MediaPresent) { + return EFI_NO_MEDIA; + } + + // + // Create a Mnp child instance, get the protocol and config for it. + // + Status = NetLibCreateServiceChild ( + Controller, + Image, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &MnpChildHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + (VOID **) &Mnp, + Image, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + MnpConfigData.ReceivedQueueTimeoutValue = 0; + MnpConfigData.TransmitQueueTimeoutValue = 0; + MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO; + MnpConfigData.EnableUnicastReceive = TRUE; + MnpConfigData.EnableMulticastReceive = TRUE; + MnpConfigData.EnableBroadcastReceive = TRUE; + MnpConfigData.EnablePromiscuousReceive = FALSE; + MnpConfigData.FlushQueuesOnReset = TRUE; + MnpConfigData.EnableReceiveTimestamps = FALSE; + MnpConfigData.DisableBackgroundPolling = FALSE; + + Status = Mnp->Configure(Mnp, &MnpConfigData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Create a DHCP4 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Controller, + Image, + &gEfiDhcp4ServiceBindingProtocolGuid, + &Dhcp4Handle + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = gBS->OpenProtocol ( + Dhcp4Handle, + &gEfiDhcp4ProtocolGuid, + (VOID **) &Dhcp4, + Image, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Get Ip4Config2 instance info. + // + Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data); + if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { + goto ON_EXIT; + } + + Data = AllocateZeroPool (DataSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data; + + // + // Build required Token. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + DhcpCommonNotify, + &IsDone, + &Token.CompletionEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff); + + Token.RemotePort = 67; + + Token.ListenPointCount = 1; + + Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT)); + if (Token.ListenPoints == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + if (Instance->Dns4CfgData.UseDefaultSetting) { + CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS)); + } else { + CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS)); + } + + Token.ListenPoints[0].ListenPort = 68; + + Token.TimeoutValue = DNS_TIME_TO_GETMAP; + + DnsInitSeedPacket (&SeedPacket, InterfaceInfo); + + ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION)); + if (ParaList[0] == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + ParaList[0]->OpCode = DHCP4_TAG_TYPE; + ParaList[0]->Length = 1; + ParaList[0]->Data[0] = DHCP4_MSG_INFORM; + + ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION)); + if (ParaList[1] == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + ParaList[1]->OpCode = DHCP4_TAG_PARA_LIST; + ParaList[1]->Length = 1; + ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER; + + Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet); + + Token.Packet->Dhcp4.Header.Xid = HTONL(NET_RANDOM (NetRandomInitSeed ())); + + Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000); + + if (Instance->Dns4CfgData.UseDefaultSetting) { + CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS)); + } else { + CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS)); + } + + CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize); + + Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize); + + // + // TransmitReceive Token + // + Status = Dhcp4->TransmitReceive (Dhcp4, &Token); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Poll the packet + // + do { + Status = Mnp->Poll (Mnp); + } while (!IsDone); + + // + // Parse the ACK to get required information if received done. + // + if (IsDone && !EFI_ERROR (Token.Status)) { + for (Index = 0; Index < Token.ResponseCount; Index++) { + Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor); + if (!EFI_ERROR (Status)) { + break; + } + } + + *DnsServerList = DnsServerInfor.ServerList; + } else { + Status = Token.Status; + } + +ON_EXIT: + + if (Data != NULL) { + FreePool (Data); + } + + for (Index = 0; Index < 2; Index++) { + if (ParaList[Index] != NULL) { + FreePool (ParaList[Index]); + } + } + + if (Token.ListenPoints) { + FreePool (Token.ListenPoints); + } + + if (Token.Packet) { + FreePool (Token.Packet); + } + + if (Token.ResponseList != NULL) { + FreePool (Token.ResponseList); + } + + if (Token.CompletionEvent != NULL) { + gBS->CloseEvent (Token.CompletionEvent); + } + + if (Dhcp4 != NULL) { + Dhcp4->Stop (Dhcp4); + Dhcp4->Configure (Dhcp4, NULL); + + gBS->CloseProtocol ( + Dhcp4Handle, + &gEfiDhcp4ProtocolGuid, + Image, + Controller + ); + } + + if (Dhcp4Handle != NULL) { + NetLibDestroyServiceChild ( + Controller, + Image, + &gEfiDhcp4ServiceBindingProtocolGuid, + Dhcp4Handle + ); + } + + if (Mnp != NULL) { + Mnp->Configure (Mnp, NULL); + + gBS->CloseProtocol ( + MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + Image, + Controller + ); + } + + NetLibDestroyServiceChild ( + Controller, + Image, + &gEfiManagedNetworkServiceBindingProtocolGuid, + MnpChildHandle + ); + + return Status; +} + +/** + Parse the DHCP ACK to get Dns6 server information. + + @param Image The handle of the driver image. + @param Controller The handle of the controller. + @param DnsServerCount Retrieved Dns6 server Ip count. + @param DnsServerList Retrieved Dns6 server Ip list. + + @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_NO_MEDIA There was a media error. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +GetDns6ServerFromDhcp6 ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + OUT UINT32 *DnsServerCount, + OUT EFI_IPv6_ADDRESS **DnsServerList + ) +{ + EFI_HANDLE Dhcp6Handle; + EFI_DHCP6_PROTOCOL *Dhcp6; + EFI_STATUS Status; + EFI_STATUS TimerStatus; + EFI_DHCP6_PACKET_OPTION *Oro; + EFI_DHCP6_RETRANSMISSION InfoReqReXmit; + EFI_EVENT Timer; + BOOLEAN MediaPresent; + DNS6_SERVER_INFOR DnsServerInfor; + + Dhcp6Handle = NULL; + Dhcp6 = NULL; + Oro = NULL; + Timer = NULL; + + ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR)); + + DnsServerInfor.ServerCount = DnsServerCount; + + // + // Check media status before doing DHCP. + // + MediaPresent = TRUE; + NetLibDetectMedia (Controller, &MediaPresent); + if (!MediaPresent) { + return EFI_NO_MEDIA; + } + + // + // Create a DHCP6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Controller, + Image, + &gEfiDhcp6ServiceBindingProtocolGuid, + &Dhcp6Handle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Dhcp6Handle, + &gEfiDhcp6ProtocolGuid, + (VOID **) &Dhcp6, + Image, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1); + if (Oro == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Ask the server to reply with DNS options. + // All members in EFI_DHCP6_PACKET_OPTION are in network order. + // + Oro->OpCode = HTONS (DHCP6_TAG_DNS_REQUEST); + Oro->OpLen = HTONS (2); + Oro->Data[1] = DHCP6_TAG_DNS_SERVER; + + InfoReqReXmit.Irt = 4; + InfoReqReXmit.Mrc = 1; + InfoReqReXmit.Mrt = 10; + InfoReqReXmit.Mrd = 30; + + Status = Dhcp6->InfoRequest ( + Dhcp6, + TRUE, + Oro, + 0, + NULL, + &InfoReqReXmit, + NULL, + ParseDhcp6Ack, + &DnsServerInfor + ); + if (Status == EFI_NO_MAPPING) { + Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Timer, + TimerRelative, + DNS_TIME_TO_GETMAP * TICKS_PER_SECOND + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + do { + TimerStatus = gBS->CheckEvent (Timer); + if (!EFI_ERROR (TimerStatus)) { + Status = Dhcp6->InfoRequest ( + Dhcp6, + TRUE, + Oro, + 0, + NULL, + &InfoReqReXmit, + NULL, + ParseDhcp6Ack, + &DnsServerInfor + ); + } + } while (TimerStatus == EFI_NOT_READY); + } + + *DnsServerList = DnsServerInfor.ServerList; + +ON_EXIT: + + if (Oro != NULL) { + FreePool (Oro); + } + + if (Timer != NULL) { + gBS->CloseEvent (Timer); + } + + if (Dhcp6 != NULL) { + gBS->CloseProtocol ( + Dhcp6Handle, + &gEfiDhcp6ProtocolGuid, + Image, + Controller + ); + } + + NetLibDestroyServiceChild ( + Controller, + Image, + &gEfiDhcp6ServiceBindingProtocolGuid, + Dhcp6Handle + ); + + return Status; + +} + diff --git a/NetworkPkg/DnsDxe/DnsDhcp.h b/NetworkPkg/DnsDxe/DnsDhcp.h new file mode 100644 index 0000000000..62bf7174e1 --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsDhcp.h @@ -0,0 +1,145 @@ +/** @file +Functions implementation related with DHCPv4/v6 for DNS driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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. + +**/ + +#ifndef _DNS_DHCP_H_ +#define _DNS_DHCP_H_ + +// +// DHCP DNS related +// +#pragma pack(1) + +#define IP4_ETHER_PROTO 0x0800 + +#define DHCP4_OPCODE_REQUEST 1 +#define DHCP4_MAGIC 0x63538263 /// network byte order +#define DHCP4_TAG_EOP 255 /// End Option + +#define DHCP4_TAG_TYPE 53 +#define DHCP4_MSG_REQUEST 3 +#define DHCP4_MSG_INFORM 8 + +#define DHCP4_TAG_PARA_LIST 55 +#define DHCP4_TAG_DNS_SERVER 6 + + +#define DHCP6_TAG_DNS_REQUEST 6 +#define DHCP6_TAG_DNS_SERVER 23 + +// +// The required Dns4 server information. +// +typedef struct { + UINT32 *ServerCount; + EFI_IPv4_ADDRESS *ServerList; +} DNS4_SERVER_INFOR; + +// +// The required Dns6 server information. +// +typedef struct { + UINT32 *ServerCount; + EFI_IPv6_ADDRESS *ServerList; +} DNS6_SERVER_INFOR; + +#pragma pack() + +/** + Parse the ACK to get required information + + @param Dhcp4 The DHCP4 protocol. + @param Packet Packet waiting for parse. + @param DnsServerInfor The required Dns4 server information. + + @retval EFI_SUCCESS The DNS information is got from the DHCP ACK. + @retval EFI_NO_MAPPING DHCP failed to acquire address and other information. + @retval EFI_DEVICE_ERROR Other errors as indicated. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + +**/ +EFI_STATUS +ParseDhcp4Ack ( + IN EFI_DHCP4_PROTOCOL *Dhcp4, + IN EFI_DHCP4_PACKET *Packet, + IN DNS4_SERVER_INFOR *DnsServerInfor + ); + +/** + EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol + instance to intercept events that occurs in the DHCPv6 Information Request + exchange process. + + @param This Pointer to the EFI_DHCP6_PROTOCOL instance that + is used to configure this callback function. + @param Context Pointer to the context that is initialized in + the EFI_DHCP6_PROTOCOL.InfoRequest(). + @param Packet Pointer to Reply packet that has been received. + The EFI DHCPv6 Protocol instance is responsible + for freeing the buffer. + + @retval EFI_SUCCESS The DNS information is got from the DHCP ACK. + @retval EFI_DEVICE_ERROR Other errors as indicated. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ParseDhcp6Ack ( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_PACKET *Packet + ); + +/** + Parse the DHCP ACK to get Dns4 server information. + + @param Instance The DNS instance. + @param DnsServerCount Retrieved Dns4 server Ip count. + @param DnsServerList Retrieved Dns4 server Ip list. + + @retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_NO_MEDIA There was a media error. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +GetDns4ServerFromDhcp4 ( + IN DNS_INSTANCE *Instance, + OUT UINT32 *DnsServerCount, + OUT EFI_IPv4_ADDRESS **DnsServerList + ); + +/** + Parse the DHCP ACK to get Dns6 server information. + + @param Image The handle of the driver image. + @param Controller The handle of the controller. + @param DnsServerCount Retrieved Dns6 server Ip count. + @param DnsServerList Retrieved Dns6 server Ip list. + + @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_NO_MEDIA There was a media error. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +GetDns6ServerFromDhcp6 ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + OUT UINT32 *DnsServerCount, + OUT EFI_IPv6_ADDRESS **DnsServerList + ); + +#endif \ No newline at end of file diff --git a/NetworkPkg/DnsDxe/DnsDriver.c b/NetworkPkg/DnsDxe/DnsDriver.c new file mode 100644 index 0000000000..6ca8aa7bdd --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsDriver.c @@ -0,0 +1,1554 @@ +/** @file +The driver binding and service binding protocol for DnsDxe driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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. + // + if (DnsSb->IpVersion == IP_VERSION_4) { + 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 availabe 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 availabe 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; +} diff --git a/NetworkPkg/DnsDxe/DnsDriver.h b/NetworkPkg/DnsDxe/DnsDriver.h new file mode 100644 index 0000000000..f6b8a7e8fc --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsDriver.h @@ -0,0 +1,606 @@ +/** @file +The header files of the driver binding and service binding protocol for DnsDxe driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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. + +**/ + +#ifndef _DNS_DRIVER_H_ +#define _DNS_DRIVER_H_ + +#include +#include + +/// +/// Dns service block +/// +typedef struct _DNS_DRIVER_DATA DNS_DRIVER_DATA; + +/// +/// Dns service block +/// +typedef struct _DNS_SERVICE DNS_SERVICE; + +/// +/// Dns instance block +/// +typedef struct _DNS_INSTANCE DNS_INSTANCE; + +#define DNS_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'N', 'S', 'S') + +#define DNS_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'N', 'S', 'I') + +struct _DNS_DRIVER_DATA { + EFI_EVENT Timer; /// Ticking timer for DNS cache update. + + LIST_ENTRY Dns4CacheList; + LIST_ENTRY Dns4ServerList; + + LIST_ENTRY Dns6CacheList; + LIST_ENTRY Dns6ServerList; +}; + +struct _DNS_SERVICE { + UINT32 Signature; + EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; + + UINT16 Dns4ChildrenNum; + LIST_ENTRY Dns4ChildrenList; + + UINT16 Dns6ChildrenNum; + LIST_ENTRY Dns6ChildrenList; + + EFI_HANDLE ControllerHandle; + EFI_HANDLE ImageHandle; + + EFI_EVENT TimerToGetMap; + + EFI_EVENT Timer; /// Ticking timer for packet retransmission. + + UINT8 IpVersion; + UDP_IO *ConnectUdp; +}; + +struct _DNS_INSTANCE { + UINT32 Signature; + LIST_ENTRY Link; + + EFI_DNS4_PROTOCOL Dns4; + EFI_DNS6_PROTOCOL Dns6; + + INTN State; + BOOLEAN InDestroy; + + DNS_SERVICE *Service; + EFI_HANDLE ChildHandle; + + EFI_DNS4_CONFIG_DATA Dns4CfgData; + EFI_DNS6_CONFIG_DATA Dns6CfgData; + + EFI_IP_ADDRESS SessionDnsServer; + + NET_MAP Dns4TxTokens; + NET_MAP Dns6TxTokens; + + UINT32 MaxRetry; + + UDP_IO *UdpIo; +}; + +typedef struct { + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UINTN NumberOfChildren; + EFI_HANDLE *ChildHandleBuffer; +} DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT; + +extern DNS_DRIVER_DATA *mDriverData; + +#define DNS_SERVICE_FROM_THIS(a) \ + CR (a, DNS_SERVICE, ServiceBinding, DNS_SERVICE_SIGNATURE) + +#define DNS_INSTANCE_FROM_THIS_PROTOCOL4(a) \ + CR (a, DNS_INSTANCE, Dns4, DNS_INSTANCE_SIGNATURE) + +#define DNS_INSTANCE_FROM_THIS_PROTOCOL6(a) \ + CR (a, DNS_INSTANCE, Dns6, DNS_INSTANCE_SIGNATURE) + + +/** + Destroy the DNS instance and recycle the resources. + + @param[in] Instance The pointer to the DNS instance. + +**/ +VOID +DnsDestroyInstance ( + IN DNS_INSTANCE *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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Release all the resource used the DNS service binding instance. + + @param DnsSb The Dns service binding instance. + +**/ +VOID +DnsDestroyService ( + IN DNS_SERVICE *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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 availabe 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 + ); + +/** + 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 + ); + +/** + 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 availabe 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 + ); + +/** + 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 + ); + + +#endif diff --git a/NetworkPkg/DnsDxe/DnsDxe.inf b/NetworkPkg/DnsDxe/DnsDxe.inf new file mode 100644 index 0000000000..bed0bd399e --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsDxe.inf @@ -0,0 +1,76 @@ +## @file +# Implementation of EFI_DNS4_PROTOCOL and EFI_DNS6_PROTOCOL interfaces. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DnsDxe + FILE_GUID = b219e140-dffc-11e3-b956-0022681e6906 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DnsDriverEntryPoint + UNLOAD_IMAGE = DnsUnload + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Sources] + ComponentName.c + DnsDriver.h + DnsDriver.c + DnsImpl.h + DnsImpl.c + DnsProtocol.c + DnsDhcp.h + DnsDhcp.c + + +[LibraryClasses] + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + MemoryAllocationLib + NetLib + DebugLib + DpcLib + PrintLib + UdpIoLib + + +[Protocols] + gEfiDns4ServiceBindingProtocolGuid ## BY_START + gEfiDns4ProtocolGuid ## BY_START + gEfiUdp4ServiceBindingProtocolGuid ## TO_START + gEfiUdp4ProtocolGuid ## BY_START + gEfiDhcp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDhcp4ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiManagedNetworkProtocolGuid ## SOMETIMES_CONSUMES + + gEfiDns6ServiceBindingProtocolGuid ## BY_START + gEfiDns6ProtocolGuid ## BY_START + gEfiUdp6ServiceBindingProtocolGuid ## TO_START + gEfiUdp6ProtocolGuid ## TO_START + gEfiDhcp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDhcp6ProtocolGuid ## SOMETIMES_CONSUMES + + +[Guids] + diff --git a/NetworkPkg/DnsDxe/DnsImpl.c b/NetworkPkg/DnsDxe/DnsImpl.c new file mode 100644 index 0000000000..c227093986 --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsImpl.c @@ -0,0 +1,1875 @@ +/** @file +DnsDxe support functions implementation. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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" + +/** + Remove TokenEntry from TokenMap. + + @param[in] TokenMap All DNSv4 Token entrys. + @param[in] TokenEntry TokenEntry need to be removed. + + @retval EFI_SUCCESS Remove TokenEntry from TokenMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +Dns4RemoveTokenEntry ( + IN NET_MAP *TokenMap, + IN DNS4_TOKEN_ENTRY *TokenEntry + ) +{ + NET_MAP_ITEM *Item; + + // + // Find the TokenEntry first. + // + Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry); + + if (Item != NULL) { + // + // Remove the TokenEntry if it's found in the map. + // + NetMapRemoveItem (TokenMap, Item, NULL); + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + Remove TokenEntry from TokenMap. + + @param[in] TokenMap All DNSv6 Token entrys. + @param[in] TokenEntry TokenEntry need to be removed. + + @retval EFI_SUCCESS Remove TokenEntry from TokenMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +Dns6RemoveTokenEntry ( + IN NET_MAP *TokenMap, + IN DNS6_TOKEN_ENTRY *TokenEntry + ) +{ + NET_MAP_ITEM *Item; + + // + // Find the TokenEntry first. + // + Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry); + + if (Item != NULL) { + // + // Remove the TokenEntry if it's found in the map. + // + NetMapRemoveItem (TokenMap, Item, NULL); + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + This function cancle the token specified by Arg in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled. If NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL, or the token + is not the same as that in the Item, if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Dns4CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + DNS4_TOKEN_ENTRY *TokenEntry; + NET_BUF *Packet; + UDP_IO *UdpIo; + + if ((Arg != NULL) && (Item->Key != Arg)) { + return EFI_SUCCESS; + } + + if (Item->Value != NULL) { + // + // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in + // Item->Value. + // + Packet = (NET_BUF *) (Item->Value); + UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0])); + + UdpIoCancelSentDatagram (UdpIo, Packet); + } + + // + // Remove TokenEntry from Dns4TxTokens. + // + TokenEntry = (DNS4_TOKEN_ENTRY *) Item->Key; + if (Dns4RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) { + TokenEntry->Token->Status = EFI_ABORTED; + gBS->SignalEvent (TokenEntry->Token->Event); + DispatchDpc (); + } + + if (Arg != NULL) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + This function cancle the token specified by Arg in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled. If NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL, or the token + is not the same as that in the Item, if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Dns6CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + DNS6_TOKEN_ENTRY *TokenEntry; + NET_BUF *Packet; + UDP_IO *UdpIo; + + if ((Arg != NULL) && (Item->Key != Arg)) { + return EFI_SUCCESS; + } + + if (Item->Value != NULL) { + // + // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in + // Item->Value. + // + Packet = (NET_BUF *) (Item->Value); + UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0])); + + UdpIoCancelSentDatagram (UdpIo, Packet); + } + + // + // Remove TokenEntry from Dns6TxTokens. + // + TokenEntry = (DNS6_TOKEN_ENTRY *) Item->Key; + if (Dns6RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) { + TokenEntry->Token->Status = EFI_ABORTED; + gBS->SignalEvent (TokenEntry->Token->Event); + DispatchDpc (); + } + + if (Arg != NULL) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + Get the TokenEntry from the TokensMap. + + @param[in] TokensMap All DNSv4 Token entrys + @param[in] Token Pointer to the token to be get. + @param[out] TokenEntry Pointer to TokenEntry corresponding Token. + + @retval EFI_SUCCESS Get the TokenEntry from the TokensMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +EFIAPI +GetDns4TokenEntry ( + IN NET_MAP *TokensMap, + IN EFI_DNS4_COMPLETION_TOKEN *Token, + OUT DNS4_TOKEN_ENTRY **TokenEntry + ) +{ + LIST_ENTRY *Entry; + + NET_MAP_ITEM *Item; + + NET_LIST_FOR_EACH (Entry, &TokensMap->Used) { + Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + *TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key); + if ((*TokenEntry)->Token == Token) { + return EFI_SUCCESS; + } + } + + *TokenEntry = NULL; + + return EFI_NOT_FOUND; +} + +/** + Get the TokenEntry from the TokensMap. + + @param[in] TokensMap All DNSv6 Token entrys + @param[in] Token Pointer to the token to be get. + @param[out] TokenEntry Pointer to TokenEntry corresponding Token. + + @retval EFI_SUCCESS Get the TokenEntry from the TokensMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +EFIAPI +GetDns6TokenEntry ( + IN NET_MAP *TokensMap, + IN EFI_DNS6_COMPLETION_TOKEN *Token, + OUT DNS6_TOKEN_ENTRY **TokenEntry + ) +{ + LIST_ENTRY *Entry; + + NET_MAP_ITEM *Item; + + NET_LIST_FOR_EACH (Entry, &TokensMap->Used) { + Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + *TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key); + if ((*TokenEntry)->Token == Token) { + return EFI_SUCCESS; + } + } + + *TokenEntry =NULL; + + return EFI_NOT_FOUND; +} + +/** + Cancel DNS4 tokens from the DNS4 instance. + + @param[in] Instance Pointer to the DNS instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Dns4InstanceCancelToken ( + IN DNS_INSTANCE *Instance, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + DNS4_TOKEN_ENTRY *TokenEntry; + + TokenEntry = NULL; + + if(Token != NULL ) { + Status = GetDns4TokenEntry (&Instance->Dns4TxTokens, Token, &TokenEntry); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + TokenEntry = NULL; + } + + // + // Cancel this TokenEntry from the Dns4TxTokens map. + // + Status = NetMapIterate (&Instance->Dns4TxTokens, Dns4CancelTokens, TokenEntry); + + if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) { + // + // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from + // the Dns4TxTokens and returns success. + // + if (NetMapIsEmpty (&Instance->Dns4TxTokens)) { + Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4); + } + return EFI_SUCCESS; + } + + ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns4TxTokens))); + + if (NetMapIsEmpty (&Instance->Dns4TxTokens)) { + Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4); + } + + return EFI_SUCCESS; +} + +/** + Cancel DNS6 tokens from the DNS6 instance. + + @param[in] Instance Pointer to the DNS instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Dns6InstanceCancelToken ( + IN DNS_INSTANCE *Instance, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + DNS6_TOKEN_ENTRY *TokenEntry; + + TokenEntry = NULL; + + if(Token != NULL ) { + Status = GetDns6TokenEntry (&Instance->Dns6TxTokens, Token, &TokenEntry); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + TokenEntry = NULL; + } + + // + // Cancel this TokenEntry from the Dns6TxTokens map. + // + Status = NetMapIterate (&Instance->Dns6TxTokens, Dns6CancelTokens, TokenEntry); + + if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) { + // + // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from + // the Dns6TxTokens and returns success. + // + if (NetMapIsEmpty (&Instance->Dns6TxTokens)) { + Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6); + } + return EFI_SUCCESS; + } + + ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns6TxTokens))); + + if (NetMapIsEmpty (&Instance->Dns6TxTokens)) { + Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6); + } + + return EFI_SUCCESS; +} + +/** + Free the resource related to the configure parameters. + + @param Config The DNS configure data + +**/ +VOID +Dns4CleanConfigure ( + IN OUT EFI_DNS4_CONFIG_DATA *Config + ) +{ + if (Config->DnsServerList != NULL) { + FreePool (Config->DnsServerList); + } + + ZeroMem (Config, sizeof (EFI_DNS4_CONFIG_DATA)); +} + +/** + Free the resource related to the configure parameters. + + @param Config The DNS configure data + +**/ +VOID +Dns6CleanConfigure ( + IN OUT EFI_DNS6_CONFIG_DATA *Config + ) +{ + if (Config->DnsServerList != NULL) { + FreePool (Config->DnsServerList); + } + + ZeroMem (Config, sizeof (EFI_DNS6_CONFIG_DATA)); +} + +/** + Allocate memory for configure parameter such as timeout value for Dst, + then copy the configure parameter from Src to Dst. + + @param[out] Dst The destination DHCP configure data. + @param[in] Src The source DHCP configure data. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_SUCCESS The configure is copied. + +**/ +EFI_STATUS +Dns4CopyConfigure ( + OUT EFI_DNS4_CONFIG_DATA *Dst, + IN EFI_DNS4_CONFIG_DATA *Src + ) +{ + UINTN Len; + UINT32 Index; + + CopyMem (Dst, Src, sizeof (*Dst)); + Dst->DnsServerList = NULL; + + // + // Allocate a memory then copy DnsServerList to it + // + if (Src->DnsServerList != NULL) { + Len = Src->DnsServerListCount * sizeof (EFI_IPv4_ADDRESS); + Dst->DnsServerList = AllocatePool (Len); + if (Dst->DnsServerList == NULL) { + Dns4CleanConfigure (Dst); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < Src->DnsServerListCount; Index++) { + CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv4_ADDRESS)); + } + } + + return EFI_SUCCESS; +} + +/** + Allocate memory for configure parameter such as timeout value for Dst, + then copy the configure parameter from Src to Dst. + + @param[out] Dst The destination DHCP configure data. + @param[in] Src The source DHCP configure data. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_SUCCESS The configure is copied. + +**/ +EFI_STATUS +Dns6CopyConfigure ( + OUT EFI_DNS6_CONFIG_DATA *Dst, + IN EFI_DNS6_CONFIG_DATA *Src + ) +{ + UINTN Len; + UINT32 Index; + + CopyMem (Dst, Src, sizeof (*Dst)); + Dst->DnsServerList = NULL; + + // + // Allocate a memory then copy DnsServerList to it + // + if (Src->DnsServerList != NULL) { + Len = Src->DnsServerCount * sizeof (EFI_IPv6_ADDRESS); + Dst->DnsServerList = AllocatePool (Len); + if (Dst->DnsServerList == NULL) { + Dns6CleanConfigure (Dst); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < Src->DnsServerCount; Index++) { + CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv6_ADDRESS)); + } + } + + return EFI_SUCCESS; +} + +/** + Callback of Dns packet. Does nothing. + + @param Arg The context. + +**/ +VOID +EFIAPI +DnsDummyExtFree ( + IN VOID *Arg + ) +{ +} + +/** + Poll the UDP to get the IP4 default address, which may be retrieved + by DHCP. + + The default time out value is 5 seconds. If IP has retrieved the default address, + the UDP is reconfigured. + + @param Instance The DNS instance + @param UdpIo The UDP_IO to poll + @param UdpCfgData The UDP configure data to reconfigure the UDP_IO + + @retval TRUE The default address is retrieved and UDP is reconfigured. + @retval FALSE Some error occured. + +**/ +BOOLEAN +Dns4GetMapping ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo, + IN EFI_UDP4_CONFIG_DATA *UdpCfgData + ) +{ + DNS_SERVICE *Service; + EFI_IP4_MODE_DATA Ip4Mode; + EFI_UDP4_PROTOCOL *Udp; + EFI_STATUS Status; + + ASSERT (Instance->Dns4CfgData.UseDefaultSetting); + + Service = Instance->Service; + Udp = UdpIo->Protocol.Udp4; + + Status = gBS->SetTimer ( + Service->TimerToGetMap, + TimerRelative, + DNS_TIME_TO_GETMAP * TICKS_PER_SECOND + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) { + Udp->Poll (Udp); + + if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) && + Ip4Mode.IsConfigured) { + + Udp->Configure (Udp, NULL); + return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS); + } + } + + return FALSE; +} + +/** + Configure the opened Udp6 instance until the corresponding Ip6 instance + has been configured. + + @param Instance The DNS instance + @param UdpIo The UDP_IO to poll + @param UdpCfgData The UDP configure data to reconfigure the UDP_IO + + @retval TRUE Configure the Udp6 instance successfully. + @retval FALSE Some error occured. + +**/ +BOOLEAN +Dns6GetMapping ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo, + IN EFI_UDP6_CONFIG_DATA *UdpCfgData + ) +{ + DNS_SERVICE *Service; + EFI_IP6_MODE_DATA Ip6Mode; + EFI_UDP6_PROTOCOL *Udp; + EFI_STATUS Status; + + Service = Instance->Service; + Udp = UdpIo->Protocol.Udp6; + + Status = gBS->SetTimer ( + Service->TimerToGetMap, + TimerRelative, + DNS_TIME_TO_GETMAP * TICKS_PER_SECOND + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) { + Udp->Poll (Udp); + + if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip6Mode, NULL, NULL)) && + Ip6Mode.IsConfigured) { + + Udp->Configure (Udp, NULL); + return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS); + } + } + + return FALSE; +} + +/** + Configure the UDP. + + @param Instance The DNS session + @param UdpIo The UDP_IO instance + + @retval EFI_SUCCESS The UDP is successfully configured for the + session. + +**/ +EFI_STATUS +Dns4ConfigUdp ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo + ) +{ + EFI_DNS4_CONFIG_DATA *Config; + EFI_UDP4_CONFIG_DATA UdpConfig; + EFI_STATUS Status; + + Config = &Instance->Dns4CfgData; + + UdpConfig.AcceptBroadcast = FALSE; + UdpConfig.AcceptPromiscuous = FALSE; + UdpConfig.AcceptAnyPort = FALSE; + UdpConfig.AllowDuplicatePort = FALSE; + UdpConfig.TypeOfService = 0; + UdpConfig.TimeToLive = 128; + UdpConfig.DoNotFragment = FALSE; + UdpConfig.ReceiveTimeout = 0; + UdpConfig.TransmitTimeout = 0; + UdpConfig.UseDefaultAddress = Config->UseDefaultSetting; + UdpConfig.SubnetMask = Config->SubnetMask; + UdpConfig.StationPort = Config->LocalPort; + UdpConfig.RemotePort = DNS_SERVER_PORT; + + CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS)); + + Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig); + + if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) { + return EFI_SUCCESS; + } + + return Status; +} + +/** + Configure the UDP. + + @param Instance The DNS session + @param UdpIo The UDP_IO instance + + @retval EFI_SUCCESS The UDP is successfully configured for the + session. + +**/ +EFI_STATUS +Dns6ConfigUdp ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo + ) +{ + EFI_DNS6_CONFIG_DATA *Config; + EFI_UDP6_CONFIG_DATA UdpConfig; + EFI_STATUS Status; + + Config = &Instance->Dns6CfgData; + + UdpConfig.AcceptPromiscuous = FALSE; + UdpConfig.AcceptAnyPort = FALSE; + UdpConfig.AllowDuplicatePort = FALSE; + UdpConfig.TrafficClass = 0; + UdpConfig.HopLimit = 128; + UdpConfig.ReceiveTimeout = 0; + UdpConfig.TransmitTimeout = 0; + UdpConfig.StationPort = Config->LocalPort; + UdpConfig.RemotePort = DNS_SERVER_PORT; + CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS)); + + Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig); + + if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) { + return EFI_SUCCESS; + } + + return Status; +} + +/** + Update Dns4 cache to shared list of caches of all DNSv4 instances. + + @param Dns4CacheList All Dns4 cache list. + @param DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param DnsCacheEntry Entry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS Update Dns4 cache successfully. + @retval Others Failed to update Dns4 cache. + +**/ +EFI_STATUS +EFIAPI +UpdateDns4Cache ( + IN LIST_ENTRY *Dns4CacheList, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry + ) +{ + DNS4_CACHE *NewDnsCache; + DNS4_CACHE *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + NewDnsCache = NULL; + Item = NULL; + + // + // Search the database for the matching EFI_DNS_CACHE_ENTRY + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \ + CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) { + // + // This is the Dns cache entry + // + if (DeleteFlag) { + // + // Delete matching DNS Cache entry + // + RemoveEntryList (&Item->AllCacheLink); + + return EFI_SUCCESS; + } else if (Override) { + // + // Update this one + // + Item->DnsCache.Timeout = DnsCacheEntry.Timeout; + + return EFI_SUCCESS; + }else { + return EFI_ACCESS_DENIED; + } + } + } + + // + // Add new one + // + NewDnsCache = AllocatePool (sizeof (DNS4_CACHE)); + if (NewDnsCache == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&NewDnsCache->AllCacheLink); + + NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName)); + if (NewDnsCache->DnsCache.HostName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName)); + + NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS)); + if (NewDnsCache->DnsCache.IpAddress == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS)); + + NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout; + + InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink); + + return EFI_SUCCESS; +} + +/** + Update Dns6 cache to shared list of caches of all DNSv6 instances. + + @param Dns6CacheList All Dns6 cache list. + @param DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param DnsCacheEntry Entry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS Update Dns6 cache successfully. + @retval Others Failed to update Dns6 cache. +**/ +EFI_STATUS +EFIAPI +UpdateDns6Cache ( + IN LIST_ENTRY *Dns6CacheList, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry + ) +{ + DNS6_CACHE *NewDnsCache; + DNS6_CACHE *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + NewDnsCache = NULL; + Item = NULL; + + // + // Search the database for the matching EFI_DNS_CACHE_ENTRY + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \ + CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) { + // + // This is the Dns cache entry + // + if (DeleteFlag) { + // + // Delete matching DNS Cache entry + // + RemoveEntryList (&Item->AllCacheLink); + + return EFI_SUCCESS; + } else if (Override) { + // + // Update this one + // + Item->DnsCache.Timeout = DnsCacheEntry.Timeout; + + return EFI_SUCCESS; + }else { + return EFI_ACCESS_DENIED; + } + } + } + + // + // Add new one + // + NewDnsCache = AllocatePool (sizeof (DNS6_CACHE)); + if (NewDnsCache == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&NewDnsCache->AllCacheLink); + + NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName)); + if (NewDnsCache->DnsCache.HostName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName)); + + NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS)); + if (NewDnsCache->DnsCache.IpAddress == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS)); + + NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout; + + InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink); + + return EFI_SUCCESS; +} + +/** + Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server. + + @param Dns4ServerList Common list of addresses of all configured DNSv4 server. + @param ServerIp DNS server Ip. + + @retval EFI_SUCCESS Add Dns4 ServerIp to common list successfully. + @retval Others Failed to add Dns4 ServerIp to common list. + +**/ +EFI_STATUS +EFIAPI +AddDns4ServerIp ( + IN LIST_ENTRY *Dns4ServerList, + IN EFI_IPv4_ADDRESS ServerIp + ) +{ + DNS4_SERVER_IP *NewServerIp; + DNS4_SERVER_IP *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + NewServerIp = NULL; + Item = NULL; + + // + // Search the database for the matching ServerIp + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink); + if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) { + // + // Already done. + // + return EFI_SUCCESS; + } + } + + // + // Add new one + // + NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP)); + if (NewServerIp == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&NewServerIp->AllServerLink); + + CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)); + + InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink); + + return EFI_SUCCESS; +} + +/** + Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server. + + @param Dns6ServerList Common list of addresses of all configured DNSv6 server. + @param ServerIp DNS server Ip. + + @retval EFI_SUCCESS Add Dns6 ServerIp to common list successfully. + @retval Others Failed to add Dns6 ServerIp to common list. + +**/ +EFI_STATUS +EFIAPI +AddDns6ServerIp ( + IN LIST_ENTRY *Dns6ServerList, + IN EFI_IPv6_ADDRESS ServerIp + ) +{ + DNS6_SERVER_IP *NewServerIp; + DNS6_SERVER_IP *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + NewServerIp = NULL; + Item = NULL; + + // + // Search the database for the matching ServerIp + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink); + if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) { + // + // Already done. + // + return EFI_SUCCESS; + } + } + + // + // Add new one + // + NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP)); + if (NewServerIp == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&NewServerIp->AllServerLink); + + CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)); + + InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink); + + return EFI_SUCCESS; +} + +/** + Find out whether the response is valid or invalid. + + @param TokensMap All DNS transmittal Tokens entry. + @param Identification Identification for queried packet. + @param Type Type for queried packet. + @param Item Return corresponding Token entry. + + @retval TRUE The response is valid. + @retval FALSE The response is invalid. + +**/ +BOOLEAN +IsValidDnsResponse ( + IN NET_MAP *TokensMap, + IN UINT16 Identification, + IN UINT16 Type, + OUT NET_MAP_ITEM **Item + ) +{ + LIST_ENTRY *Entry; + + NET_BUF *Packet; + UINT8 *TxString; + DNS_HEADER *DnsHeader; + CHAR8 *QueryName; + DNS_QUERY_SECTION *QuerySection; + + NET_LIST_FOR_EACH (Entry, &TokensMap->Used) { + *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + Packet = (NET_BUF *) ((*Item)->Value); + if (Packet == NULL){ + + continue; + } else { + TxString = NetbufGetByte (Packet, 0, NULL); + DnsHeader = (DNS_HEADER *) TxString; + QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader)); + QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1); + + DnsHeader->Identification = NTOHS (DnsHeader->Identification); + QuerySection->Type = NTOHS (QuerySection->Type); + + if (DnsHeader->Identification == Identification && QuerySection->Type == Type) { + return TRUE; + } + } + } + + *Item =NULL; + + return FALSE; +} + +/** + Parse Dns Response. + + @param Instance The DNS instance + @param RxString Received buffer. + @param Completed Flag to indicate that Dns response is valid. + + @retval EFI_SUCCESS Parse Dns Response successfully. + @retval Others Failed to parse Dns Response. + +**/ +EFI_STATUS +ParseDnsResponse ( + IN OUT DNS_INSTANCE *Instance, + IN UINT8 *RxString, + OUT BOOLEAN *Completed + ) +{ + DNS_HEADER *DnsHeader; + + CHAR8 *QueryName; + DNS_QUERY_SECTION *QuerySection; + + CHAR8 *AnswerName; + DNS_ANSWER_SECTION *AnswerSection; + UINT8 *AnswerData; + + NET_MAP_ITEM *Item; + DNS4_TOKEN_ENTRY *Dns4TokenEntry; + DNS6_TOKEN_ENTRY *Dns6TokenEntry; + + UINT32 IpCount; + UINT32 AnswerSectionNum; + + EFI_IPv4_ADDRESS *HostAddr4; + EFI_IPv6_ADDRESS *HostAddr6; + + EFI_DNS4_CACHE_ENTRY *Dns4CacheEntry; + EFI_DNS6_CACHE_ENTRY *Dns6CacheEntry; + + EFI_STATUS Status; + + EFI_TPL OldTpl; + + Item = NULL; + Dns4TokenEntry = NULL; + Dns6TokenEntry = NULL; + + IpCount = 0; + AnswerSectionNum = 0; + + HostAddr4 = NULL; + HostAddr6 = NULL; + + Dns4CacheEntry = NULL; + Dns6CacheEntry = NULL; + + *Completed = TRUE; + Status = EFI_SUCCESS; + + // + // Get header + // + DnsHeader = (DNS_HEADER *) RxString; + + DnsHeader->Identification = NTOHS (DnsHeader->Identification); + DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16); + DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum); + DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum); + DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum); + DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum); + + // + // Get Query name + // + QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader)); + + // + // Get query section + // + QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1); + QuerySection->Type = NTOHS (QuerySection->Type); + QuerySection->Class = NTOHS (QuerySection->Class); + + // + // Get Answer name + // + AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM. + // + if (Instance->Service->IpVersion == IP_VERSION_4) { + if (!IsValidDnsResponse (&Instance->Dns4TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) { + *Completed = FALSE; + Status = EFI_ABORTED; + goto ON_EXIT; + } + ASSERT (Item != NULL); + Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key); + } else { + if (!IsValidDnsResponse (&Instance->Dns6TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) { + *Completed = FALSE; + Status = EFI_ABORTED; + goto ON_EXIT; + } + ASSERT (Item != NULL); + Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key); + } + + // + // Continue Check Some Errors. + // + if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \ + DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE || QuerySection->Class != DNS_CLASS_INET) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + + // + // Free the sending packet. + // + if (Item->Value != NULL) { + NetbufFree ((NET_BUF *) (Item->Value)); + } + + // + // Check the Query type, do some buffer allocations. + // + if (QuerySection->Type == DNS_TYPE_A) { + Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA)); + ASSERT (Dns4TokenEntry->Token->RspData.H2AData != NULL); + Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS)); + ASSERT (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL); + } else if (QuerySection->Type == DNS_TYPE_AAAA) { + Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA)); + ASSERT (Dns6TokenEntry->Token->RspData.H2AData != NULL); + Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS)); + ASSERT (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL); + } else { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Processing AnswerSection. + // + while (AnswerSectionNum < DnsHeader->AnswersNum) { + // + // Answer name should be PTR. + // + ASSERT ((*(UINT8 *) AnswerName & 0xC0) == 0xC0); + + // + // Get Answer section. + // + AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16)); + AnswerSection->Type = NTOHS (AnswerSection->Type); + AnswerSection->Class = NTOHS (AnswerSection->Class); + AnswerSection->Ttl = NTOHL (AnswerSection->Ttl); + AnswerSection->DataLength = NTOHS (AnswerSection->DataLength); + + ASSERT (AnswerSection->Class == DNS_CLASS_INET); + + if (AnswerSection->Type == QuerySection->Type) { + switch (AnswerSection->Type) { + case DNS_TYPE_A: + // + // This is address entry, get Data. + // + ASSERT (AnswerSection->DataLength == 4); + + HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList; + AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection); + CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS)); + + // + // Update DNS cache dynamically. + // + if (Dns4CacheEntry != NULL) { + if (Dns4CacheEntry->HostName != NULL) { + FreePool (Dns4CacheEntry->HostName); + } + + if (Dns4CacheEntry->IpAddress != NULL) { + FreePool (Dns4CacheEntry->IpAddress); + } + + FreePool (Dns4CacheEntry); + } + + // + // Allocate new CacheEntry pool. + // + Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY)); + ASSERT (Dns4CacheEntry != NULL); + Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1)); + ASSERT (Dns4CacheEntry->HostName != NULL); + CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1)); + Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS)); + ASSERT (Dns4CacheEntry->IpAddress != NULL); + CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS)); + Dns4CacheEntry->Timeout = AnswerSection->Ttl; + + UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry); + + IpCount ++; + break; + case DNS_TYPE_AAAA: + // + // This is address entry, get Data. + // + ASSERT (AnswerSection->DataLength == 16); + + HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList; + AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection); + CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS)); + + // + // Update DNS cache dynamically. + // + if (Dns6CacheEntry != NULL) { + if (Dns6CacheEntry->HostName != NULL) { + FreePool (Dns6CacheEntry->HostName); + } + + if (Dns6CacheEntry->IpAddress != NULL) { + FreePool (Dns6CacheEntry->IpAddress); + } + + FreePool (Dns6CacheEntry); + } + + // + // Allocate new CacheEntry pool. + // + Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY)); + ASSERT (Dns6CacheEntry != NULL); + Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1)); + ASSERT (Dns6CacheEntry->HostName != NULL); + CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1)); + Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS)); + ASSERT (Dns6CacheEntry->IpAddress != NULL); + CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS)); + Dns6CacheEntry->Timeout = AnswerSection->Ttl; + + UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry); + + IpCount ++; + break; + default: + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + } + + // + // Find next one + // + AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength; + AnswerSectionNum ++; + } + + if (QuerySection->Type == DNS_TYPE_A) { + Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount; + } else if (QuerySection->Type == DNS_TYPE_AAAA) { + Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount; + } + + // + // Parsing is complete, SignalEvent here. + // + if (Instance->Service->IpVersion == IP_VERSION_4) { + Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry); + Dns4TokenEntry->Token->Status = EFI_SUCCESS; + if (Dns4TokenEntry->Token->Event != NULL) { + gBS->SignalEvent (Dns4TokenEntry->Token->Event); + DispatchDpc (); + } + } else { + Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry); + Dns6TokenEntry->Token->Status = EFI_SUCCESS; + if (Dns6TokenEntry->Token->Event != NULL) { + gBS->SignalEvent (Dns6TokenEntry->Token->Event); + DispatchDpc (); + } + } + + // + // Free allocated CacheEntry pool. + // + if (Dns4CacheEntry != NULL) { + if (Dns4CacheEntry->HostName != NULL) { + FreePool (Dns4CacheEntry->HostName); + } + + if (Dns4CacheEntry->IpAddress != NULL) { + FreePool (Dns4CacheEntry->IpAddress); + } + + FreePool (Dns4CacheEntry); + } + + if (Dns6CacheEntry != NULL) { + if (Dns6CacheEntry->HostName != NULL) { + FreePool (Dns6CacheEntry->HostName); + } + + if (Dns6CacheEntry->IpAddress != NULL) { + FreePool (Dns6CacheEntry->IpAddress); + } + + FreePool (Dns6CacheEntry); + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Parse response packet. + + @param Packet The packets received. + @param EndPoint The local/remote UDP access point + @param IoStatus The status of the UDP receive + @param Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +DnsOnPacketReceived ( + NET_BUF *Packet, + UDP_END_POINT *EndPoint, + EFI_STATUS IoStatus, + VOID *Context + ) +{ + DNS_INSTANCE *Instance; + + UINT8 *RcvString; + + BOOLEAN Completed; + + Instance = (DNS_INSTANCE *) Context; + NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE); + + RcvString = NULL; + Completed = FALSE; + + if (EFI_ERROR (IoStatus)) { + goto ON_EXIT; + } + + ASSERT (Packet != NULL); + + RcvString = NetbufGetByte (Packet, 0, NULL); + + // + // Parse Dns Response + // + ParseDnsResponse (Instance, RcvString, &Completed); + + ON_EXIT: + + if (Packet != NULL) { + NetbufFree (Packet); + } + + if (!Completed) { + UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0); + } +} + +/** + Release the net buffer when packet is sent. + + @param Packet The packets received. + @param EndPoint The local/remote UDP access point + @param IoStatus The status of the UDP receive + @param Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +DnsOnPacketSent ( + NET_BUF *Packet, + UDP_END_POINT *EndPoint, + EFI_STATUS IoStatus, + VOID *Context + ) +{ + DNS_INSTANCE *Instance; + LIST_ENTRY *Entry; + NET_MAP_ITEM *Item; + DNS4_TOKEN_ENTRY *Dns4TokenEntry; + DNS6_TOKEN_ENTRY *Dns6TokenEntry; + + Dns4TokenEntry = NULL; + Dns6TokenEntry = NULL; + + Instance = (DNS_INSTANCE *) Context; + NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE); + + if (Instance->Service->IpVersion == IP_VERSION_4) { + NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) { + Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + if (Packet == (NET_BUF *)(Item->Value)) { + Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key); + Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval; + break; + } + } + } else { + NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) { + Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + if (Packet == (NET_BUF *)(Item->Value)) { + Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key); + Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval; + break; + } + } + } + + NetbufFree (Packet); +} + +/** + Query request information. + + @param Instance The DNS instance + @param Packet The packet for querying request information. + + @retval EFI_SUCCESS Query request information successfully. + @retval Others Failed to query request information. + +**/ +EFI_STATUS +DoDnsQuery ( + IN DNS_INSTANCE *Instance, + IN NET_BUF *Packet + ) +{ + EFI_STATUS Status; + + // + // Ready to receive the DNS response. + // + if (Instance->UdpIo->RecvRequest == NULL) { + Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Transmit the DNS packet. + // + NET_GET_REF (Packet); + + Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance); + + return Status; +} + +/** + Construct the Packet to query Ip. + + @param Instance The DNS instance + @param HostName Queried HostName + @param Type DNS query Type + @param Packet The packet for querying Ip + + @retval EFI_SUCCESS The packet is constructed. + @retval Others Failed to construct the Packet. + +**/ +EFI_STATUS +ConstructDNSQueryIp ( + IN DNS_INSTANCE *Instance, + IN CHAR16 *HostName, + IN UINT16 Type, + OUT NET_BUF **Packet + ) +{ + NET_FRAGMENT Frag; + DNS_HEADER *DnsHeader; + CHAR8 *QueryName; + DNS_QUERY_SECTION *QuerySection; + CHAR8 *Header; + CHAR8 *Tail; + UINTN Len; + UINTN Index; + + + Frag.Bulk = AllocatePool (DNS_DEFAULT_BLKSIZE * sizeof (UINT8)); + if (Frag.Bulk == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Fill header + // + DnsHeader = (DNS_HEADER *)Frag.Bulk; + DnsHeader->Identification = (UINT16)AsmReadTsc (); + DnsHeader->Flags.Uint16 = 0x0000; + DnsHeader->Flags.Bits.RD = 1; + DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD; + DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY; + DnsHeader->QuestionsNum = 1; + DnsHeader->AnswersNum = 0; + DnsHeader->AuthorityNum = 0; + DnsHeader->AditionalNum = 0; + + DnsHeader->Identification = HTONS(DnsHeader->Identification); + DnsHeader->Flags.Uint16 = HTONS(DnsHeader->Flags.Uint16); + DnsHeader->QuestionsNum = HTONS(DnsHeader->QuestionsNum); + DnsHeader->AnswersNum = HTONS(DnsHeader->AnswersNum); + DnsHeader->AuthorityNum = HTONS(DnsHeader->AuthorityNum); + DnsHeader->AditionalNum = HTONS(DnsHeader->AditionalNum); + + Frag.Len = sizeof (*DnsHeader); + + // + // Fill Query name + // + QueryName = (CHAR8 *) (Frag.Bulk + Frag.Len); + Header = QueryName; + Tail = Header + 1; + Len = 0; + for (Index = 0; HostName[Index] != 0; Index++) { + *Tail = (CHAR8) HostName[Index]; + if (*Tail == '.') { + *Header = (CHAR8) Len; + Header = Tail; + Tail ++; + Len = 0; + } else { + Tail++; + Len++; + } + } + *Header = (CHAR8) Len; + *Tail = 0; + Frag.Len = (UINT32) (Frag.Len + StrLen (HostName) + 2); /// 1 for header, 1 for tail. + + // + // Rest query section + // + QuerySection = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len); + QuerySection->Type = Type; + QuerySection->Class = DNS_CLASS_INET; + + QuerySection->Type = HTONS (QuerySection->Type); + QuerySection->Class = HTONS (QuerySection->Class); + + Frag.Len += sizeof (*QuerySection); + + // + // Wrap the Frag in a net buffer. + // + *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL); + if (*Packet == NULL) { + FreePool (Frag.Bulk); + return EFI_OUT_OF_RESOURCES; + } + + // + // Store the UdpIo in ProtoData. + // + *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo); + + return EFI_SUCCESS; +} + +/** + Retransmit the packet. + + @param Instance The DNS instance + @param Packet Retransmit the packet + + @retval EFI_SUCCESS The packet is retransmitted. + @retval Others Failed to retransmit. + +**/ +EFI_STATUS +DnsRetransmit ( + IN DNS_INSTANCE *Instance, + IN NET_BUF *Packet + ) +{ + EFI_STATUS Status; + + UINT8 *Buffer; + + ASSERT (Packet != NULL); + + // + // Set the requests to the listening port, other packets to the connected port + // + Buffer = NetbufGetByte (Packet, 0, NULL); + ASSERT (Buffer != NULL); + + NET_GET_REF (Packet); + + Status = UdpIoSendDatagram ( + Instance->UdpIo, + Packet, + NULL, + NULL, + DnsOnPacketSent, + Instance + ); + + if (EFI_ERROR (Status)) { + NET_PUT_REF (Packet); + } + + return Status; +} + +/** + The timer ticking function for the DNS services. + + @param Event The ticking event + @param Context The DNS service instance + +**/ +VOID +EFIAPI +DnsOnTimerRetransmit ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + DNS_SERVICE *Service; + + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + DNS_INSTANCE *Instance; + LIST_ENTRY *EntryNetMap; + NET_MAP_ITEM *ItemNetMap; + DNS4_TOKEN_ENTRY *Dns4TokenEntry; + DNS6_TOKEN_ENTRY *Dns6TokenEntry; + + Dns4TokenEntry = NULL; + Dns6TokenEntry = NULL; + + Service = (DNS_SERVICE *) Context; + + + if (Service->IpVersion == IP_VERSION_4) { + // + // Iterate through all the children of the DNS service instance. Time + // out the packet. If maximum retries reached, clean the Token up. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) { + Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link); + + EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink; + while (EntryNetMap != &Instance->Dns4TxTokens.Used) { + ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link); + Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key); + if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) { + EntryNetMap = EntryNetMap->ForwardLink; + continue; + } + + // + // Retransmit the packet if haven't reach the maxmium retry count, + // otherwise exit the transfer. + // + if (++Dns4TokenEntry->Token->RetryCount < Instance->MaxRetry) { + DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value); + EntryNetMap = EntryNetMap->ForwardLink; + } else { + // + // Maximum retries reached, clean the Token up. + // + Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry); + Dns4TokenEntry->Token->Status = EFI_TIMEOUT; + gBS->SignalEvent (Dns4TokenEntry->Token->Event); + DispatchDpc (); + + // + // Free the sending packet. + // + if (ItemNetMap->Value != NULL) { + NetbufFree ((NET_BUF *)(ItemNetMap->Value)); + } + + EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink; + } + } + } + }else { + // + // Iterate through all the children of the DNS service instance. Time + // out the packet. If maximum retries reached, clean the Token up. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) { + Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link); + + EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink; + while (EntryNetMap != &Instance->Dns6TxTokens.Used) { + ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link); + Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key); + if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) { + EntryNetMap = EntryNetMap->ForwardLink; + continue; + } + + // + // Retransmit the packet if haven't reach the maxmium retry count, + // otherwise exit the transfer. + // + if (++Dns6TokenEntry->Token->RetryCount < Instance->MaxRetry) { + DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value); + EntryNetMap = EntryNetMap->ForwardLink; + } else { + // + // Maximum retries reached, clean the Token up. + // + Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry); + Dns6TokenEntry->Token->Status = EFI_TIMEOUT; + gBS->SignalEvent (Dns6TokenEntry->Token->Event); + DispatchDpc (); + + // + // Free the sending packet. + // + if (ItemNetMap->Value != NULL) { + NetbufFree ((NET_BUF *) (ItemNetMap->Value)); + } + + EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink; + } + } + } + } +} + +/** + The timer ticking function for the DNS driver. + + @param Event The ticking event + @param Context NULL + +**/ +VOID +EFIAPI +DnsOnTimerUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + DNS4_CACHE *Item4; + DNS6_CACHE *Item6; + + Item4 = NULL; + Item6 = NULL; + + // + // Iterate through all the DNS4 cache list. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) { + Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + Item4->DnsCache.Timeout--; + } + + Entry = mDriverData->Dns4CacheList.ForwardLink; + while (Entry != &mDriverData->Dns4CacheList) { + Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + if (Item4->DnsCache.Timeout<=0) { + RemoveEntryList (&Item4->AllCacheLink); + Entry = mDriverData->Dns4CacheList.ForwardLink; + } else { + Entry = Entry->ForwardLink; + } + } + + // + // Iterate through all the DNS6 cache list. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) { + Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + Item6->DnsCache.Timeout--; + } + + Entry = mDriverData->Dns6CacheList.ForwardLink; + while (Entry != &mDriverData->Dns6CacheList) { + Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + if (Item6->DnsCache.Timeout<=0) { + RemoveEntryList (&Item6->AllCacheLink); + Entry = mDriverData->Dns6CacheList.ForwardLink; + } else { + Entry = Entry->ForwardLink; + } + } +} + diff --git a/NetworkPkg/DnsDxe/DnsImpl.h b/NetworkPkg/DnsDxe/DnsImpl.h new file mode 100644 index 0000000000..c3a889bcd5 --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsImpl.h @@ -0,0 +1,1139 @@ +/** @file +DnsDxe support functions implementation. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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. + +**/ + +#ifndef __EFI_DNS_IMPL_H_ +#define __EFI_DNS_IMPL_H_ + +#include + +// +// Libraries classes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// UEFI Driver Model Protocols +// +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "DnsDriver.h" +#include "DnsDhcp.h" + +// +// Driver Version +// +#define DNS_VERSION 0x00000000 + +// +// Protocol instances +// +extern EFI_COMPONENT_NAME_PROTOCOL gDnsComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gDnsComponentName2; +extern EFI_UNICODE_STRING_TABLE *gDnsControllerNameTable; + +extern EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding; +extern EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding; +extern EFI_DNS4_PROTOCOL mDns4Protocol; + +extern EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding; +extern EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding; +extern EFI_DNS6_PROTOCOL mDns6Protocol; + +// +// DNS related +// +#define DNS_SERVER_PORT 53 + +#define DNS_PROTOCOL_UDP EFI_IP_PROTO_UDP +#define DNS_PROTOCOL_TCP EFI_IP_PROTO_TCP + +#define DNS_STATE_UNCONFIGED 0 +#define DNS_STATE_CONFIGED 1 +#define DNS_STATE_DESTROY 2 + +#define DNS_DEFAULT_TIMEOUT 2 +#define DNS_DEFAULT_RETRY 3 +#define DNS_DEFAULT_BLKSIZE 512 + +#define DNS_TIME_TO_GETMAP 5 + +#pragma pack(1) + +typedef union _DNS_FLAGS DNS_FLAGS; + +typedef struct { + LIST_ENTRY AllCacheLink; + EFI_DNS4_CACHE_ENTRY DnsCache; +} DNS4_CACHE; + +typedef struct { + LIST_ENTRY AllCacheLink; + EFI_DNS6_CACHE_ENTRY DnsCache; +} DNS6_CACHE; + +typedef struct { + LIST_ENTRY AllServerLink; + EFI_IPv4_ADDRESS Dns4ServerIp; +} DNS4_SERVER_IP; + +typedef struct { + LIST_ENTRY AllServerLink; + EFI_IPv6_ADDRESS Dns6ServerIp; +} DNS6_SERVER_IP; + +typedef struct { + UINT32 PacketToLive; + CHAR16 *QueryHostName; + EFI_IPv4_ADDRESS QueryIpAddress; + EFI_DNS4_COMPLETION_TOKEN *Token; +} DNS4_TOKEN_ENTRY; + +typedef struct { + UINT32 PacketToLive; + CHAR16 *QueryHostName; + EFI_IPv6_ADDRESS QueryIpAddress; + EFI_DNS6_COMPLETION_TOKEN *Token; +} DNS6_TOKEN_ENTRY; + +union _DNS_FLAGS{ + struct { + UINT16 RCode:4; + UINT16 Zero:3; + UINT16 RA:1; + UINT16 RD:1; + UINT16 TC:1; + UINT16 AA:1; + UINT16 OpCode:4; + UINT16 QR:1; + } Bits; + UINT16 Uint16; +}; + +#define DNS_FLAGS_QR_QUERY 0 +#define DNS_FLAGS_QR_RESPONSE 1 + +#define DNS_FLAGS_OPCODE_STANDARD 0 +#define DNS_FLAGS_OPCODE_INVERSE 1 +#define DNS_FLAGS_OPCODE_SERVER_STATE 2 + +#define DNS_FLAGS_RCODE_NO_ERROR 0 +#define DNS_FLAGS_RCODE_NAME_ERROR 3 + +typedef struct { + UINT16 Identification; + DNS_FLAGS Flags; + UINT16 QuestionsNum; + UINT16 AnswersNum; + UINT16 AuthorityNum; + UINT16 AditionalNum; +} DNS_HEADER; + +typedef struct { + UINT16 Type; + UINT16 Class; +} DNS_QUERY_SECTION; + +typedef struct { + UINT16 Type; + UINT16 Class; + UINT32 Ttl; + UINT16 DataLength; +} DNS_ANSWER_SECTION; + +#define DNS_TYPE_A 1 +#define DNS_TYPE_NS 2 +#define DNS_TYPE_CNAME 5 +#define DNS_TYPE_PTR 12 +#define DNS_TYPE_HINFO 13 +#define DNS_TYPE_MX 15 +#define DNS_TYPE_AAAA 28 +#define DNS_TYPE_SRV_RR 33 +#define DNS_TYPE_AXFR 252 +#define DNS_TYPE_ANY 255 + +#define DNS_CLASS_INET 1 + +#define DNS4_DOMAIN L"in-addr.arpa" +#define DNS6_DOMAIN L"IP6.ARPA" + + +#pragma pack() + +/** + Remove TokenEntry from TokenMap. + + @param[in] TokenMap All DNSv4 Token entrys. + @param[in] TokenEntry TokenEntry need to be removed. + + @retval EFI_SUCCESS Remove TokenEntry from TokenMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +Dns4RemoveTokenEntry ( + IN NET_MAP *TokenMap, + IN DNS4_TOKEN_ENTRY *TokenEntry + ); + +/** + Remove TokenEntry from TokenMap. + + @param[in] TokenMap All DNSv6 Token entrys. + @param[in] TokenEntry TokenEntry need to be removed. + + @retval EFI_SUCCESS Remove TokenEntry from TokenMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +Dns6RemoveTokenEntry ( + IN NET_MAP *TokenMap, + IN DNS6_TOKEN_ENTRY *TokenEntry + ); + +/** + This function cancle the token specified by Arg in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled. If NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL, or the token + is not the same as that in the Item, if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Dns4CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + This function cancle the token specified by Arg in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled. If NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL, or the token + is not the same as that in the Item, if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Dns6CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + Get the TokenEntry from the TokensMap. + + @param[in] TokensMap All DNSv4 Token entrys + @param[in] Token Pointer to the token to be get. + @param[out] TokenEntry Pointer to TokenEntry corresponding Token. + + @retval EFI_SUCCESS Get the TokenEntry from the TokensMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +EFIAPI +GetDns4TokenEntry ( + IN NET_MAP *TokensMap, + IN EFI_DNS4_COMPLETION_TOKEN *Token, + OUT DNS4_TOKEN_ENTRY **TokenEntry + ); + +/** + Get the TokenEntry from the TokensMap. + + @param[in] TokensMap All DNSv6 Token entrys + @param[in] Token Pointer to the token to be get. + @param[out] TokenEntry Pointer to TokenEntry corresponding Token. + + @retval EFI_SUCCESS Get the TokenEntry from the TokensMap sucessfully. + @retval EFI_NOT_FOUND TokenEntry is not found in TokenMap. + +**/ +EFI_STATUS +EFIAPI +GetDns6TokenEntry ( + IN NET_MAP *TokensMap, + IN EFI_DNS6_COMPLETION_TOKEN *Token, + OUT DNS6_TOKEN_ENTRY **TokenEntry + ); + +/** + Cancel DNS4 tokens from the DNS4 instance. + + @param[in] Instance Pointer to the DNS instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Dns4InstanceCancelToken ( + IN DNS_INSTANCE *Instance, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + Cancel DNS6 tokens from the DNS6 instance. + + @param[in] Instance Pointer to the DNS instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Dns6InstanceCancelToken ( + IN DNS_INSTANCE *Instance, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + Free the resource related to the configure parameters. + + @param Config The DNS configure data + +**/ +VOID +Dns4CleanConfigure ( + IN OUT EFI_DNS4_CONFIG_DATA *Config + ); + +/** + Free the resource related to the configure parameters. + + @param Config The DNS configure data + +**/ +VOID +Dns6CleanConfigure ( + IN OUT EFI_DNS6_CONFIG_DATA *Config + ); + +/** + Allocate memory for configure parameter such as timeout value for Dst, + then copy the configure parameter from Src to Dst. + + @param[out] Dst The destination DHCP configure data. + @param[in] Src The source DHCP configure data. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_SUCCESS The configure is copied. + +**/ +EFI_STATUS +Dns4CopyConfigure ( + OUT EFI_DNS4_CONFIG_DATA *Dst, + IN EFI_DNS4_CONFIG_DATA *Src + ); + +/** + Allocate memory for configure parameter such as timeout value for Dst, + then copy the configure parameter from Src to Dst. + + @param[out] Dst The destination DHCP configure data. + @param[in] Src The source DHCP configure data. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_SUCCESS The configure is copied. + +**/ +EFI_STATUS +Dns6CopyConfigure ( + OUT EFI_DNS6_CONFIG_DATA *Dst, + IN EFI_DNS6_CONFIG_DATA *Src + ); + +/** + Callback of Dns packet. Does nothing. + + @param Arg The context. + +**/ +VOID +EFIAPI +DnsDummyExtFree ( + IN VOID *Arg + ); + +/** + Poll the UDP to get the IP4 default address, which may be retrieved + by DHCP. + + The default time out value is 5 seconds. If IP has retrieved the default address, + the UDP is reconfigured. + + @param Instance The DNS instance + @param UdpIo The UDP_IO to poll + @param UdpCfgData The UDP configure data to reconfigure the UDP_IO + + @retval TRUE The default address is retrieved and UDP is reconfigured. + @retval FALSE Some error occured. + +**/ +BOOLEAN +Dns4GetMapping ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo, + IN EFI_UDP4_CONFIG_DATA *UdpCfgData + ); + +/** + Configure the opened Udp6 instance until the corresponding Ip6 instance + has been configured. + + @param Instance The DNS instance + @param UdpIo The UDP_IO to poll + @param UdpCfgData The UDP configure data to reconfigure the UDP_IO + + @retval TRUE Configure the Udp6 instance successfully. + @retval FALSE Some error occured. + +**/ +BOOLEAN +Dns6GetMapping ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo, + IN EFI_UDP6_CONFIG_DATA *UdpCfgData + ); + +/** + Configure the UDP. + + @param Instance The DNS session + @param UdpIo The UDP_IO instance + + @retval EFI_SUCCESS The UDP is successfully configured for the + session. + +**/ +EFI_STATUS +Dns4ConfigUdp ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo + ); + +/** + Configure the UDP. + + @param Instance The DNS session + @param UdpIo The UDP_IO instance + + @retval EFI_SUCCESS The UDP is successfully configured for the + session. + +**/ +EFI_STATUS +Dns6ConfigUdp ( + IN DNS_INSTANCE *Instance, + IN UDP_IO *UdpIo + ); + +/** + Update Dns4 cache to shared list of caches of all DNSv4 instances. + + @param Dns4CacheList All Dns4 cache list. + @param DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param DnsCacheEntry Entry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS Update Dns4 cache successfully. + @retval Others Failed to update Dns4 cache. + +**/ +EFI_STATUS +EFIAPI +UpdateDns4Cache ( + IN LIST_ENTRY *Dns4CacheList, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry + ); + +/** + Update Dns6 cache to shared list of caches of all DNSv6 instances. + + @param Dns6CacheList All Dns6 cache list. + @param DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param DnsCacheEntry Entry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS Update Dns6 cache successfully. + @retval Others Failed to update Dns6 cache. +**/ +EFI_STATUS +EFIAPI +UpdateDns6Cache ( + IN LIST_ENTRY *Dns6CacheList, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry + ); + +/** + Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server. + + @param Dns4ServerList Common list of addresses of all configured DNSv4 server. + @param ServerIp DNS server Ip. + + @retval EFI_SUCCESS Add Dns4 ServerIp to common list successfully. + @retval Others Failed to add Dns4 ServerIp to common list. + +**/ +EFI_STATUS +EFIAPI +AddDns4ServerIp ( + IN LIST_ENTRY *Dns4ServerList, + IN EFI_IPv4_ADDRESS ServerIp + ); + +/** + Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server. + + @param Dns6ServerList Common list of addresses of all configured DNSv6 server. + @param ServerIp DNS server Ip. + + @retval EFI_SUCCESS Add Dns6 ServerIp to common list successfully. + @retval Others Failed to add Dns6 ServerIp to common list. + +**/ +EFI_STATUS +EFIAPI +AddDns6ServerIp ( + IN LIST_ENTRY *Dns6ServerList, + IN EFI_IPv6_ADDRESS ServerIp + ); + +/** + Find out whether the response is valid or invalid. + + @param TokensMap All DNS transmittal Tokens entry. + @param Identification Identification for queried packet. + @param Type Type for queried packet. + @param Item Return corresponding Token entry. + + @retval TRUE The response is valid. + @retval FALSE The response is invalid. + +**/ +BOOLEAN +IsValidDnsResponse ( + IN NET_MAP *TokensMap, + IN UINT16 Identification, + IN UINT16 Type, + OUT NET_MAP_ITEM **Item + ); + +/** + Parse Dns Response. + + @param Instance The DNS instance + @param RxString Received buffer. + @param Completed Flag to indicate that Dns response is valid. + + @retval EFI_SUCCESS Parse Dns Response successfully. + @retval Others Failed to parse Dns Response. + +**/ +EFI_STATUS +ParseDnsResponse ( + IN OUT DNS_INSTANCE *Instance, + IN UINT8 *RxString, + OUT BOOLEAN *Completed + ); + +/** + Parse response packet. + + @param Packet The packets received. + @param EndPoint The local/remote UDP access point + @param IoStatus The status of the UDP receive + @param Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +DnsOnPacketReceived ( + NET_BUF *Packet, + UDP_END_POINT *EndPoint, + EFI_STATUS IoStatus, + VOID *Context + ); + +/** + Release the net buffer when packet is sent. + + @param Packet The packets received. + @param EndPoint The local/remote UDP access point + @param IoStatus The status of the UDP receive + @param Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +DnsOnPacketSent ( + NET_BUF *Packet, + UDP_END_POINT *EndPoint, + EFI_STATUS IoStatus, + VOID *Context + ); + +/** + Query request information. + + @param Instance The DNS instance + @param Packet The packet for querying request information. + + @retval EFI_SUCCESS Query request information successfully. + @retval Others Failed to query request information. + +**/ +EFI_STATUS +DoDnsQuery ( + IN DNS_INSTANCE *Instance, + IN NET_BUF *Packet + ); + +/** + Construct the Packet to query Ip. + + @param Instance The DNS instance + @param HostName Queried HostName + @param Type DNS query Type + @param Packet The packet for querying Ip + + @retval EFI_SUCCESS The packet is constructed. + @retval Others Failed to construct the Packet. + +**/ +EFI_STATUS +ConstructDNSQueryIp ( + IN DNS_INSTANCE *Instance, + IN CHAR16 *HostName, + IN UINT16 Type, + OUT NET_BUF **Packet + ); + +/** + Retransmit the packet. + + @param Instance The DNS instance + @param Packet Retransmit the packet + + @retval EFI_SUCCESS The packet is retransmitted. + @retval Others Failed to retransmit. + +**/ +EFI_STATUS +DnsRetransmit ( + IN DNS_INSTANCE *Instance, + IN NET_BUF *Packet + ); + +/** + The timer ticking function for the DNS service. + + @param Event The ticking event + @param Context The DNS service instance + +**/ +VOID +EFIAPI +DnsOnTimerRetransmit ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + The timer ticking function for the DNS driver. + + @param Event The ticking event + @param Context NULL + +**/ +VOID +EFIAPI +DnsOnTimerUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +/** + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[out] DnsModeData Pointer to the caller-allocated storage for the EFI_DNS4_MODE_DATA structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data is + available because this instance has not been configured. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + +**/ +EFI_STATUS +EFIAPI +Dns4GetModeData ( + IN EFI_DNS4_PROTOCOL *This, + OUT EFI_DNS4_MODE_DATA *DnsModeData + ); + +/** + This function is used to configure DNS configuration data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DnsConfigData Pointer to caller-allocated buffer containing EFI_DNS4_CONFIG_DATA structure. + If NULL, the driver will reinitialize the protocol instance to the unconfigured state. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not a valid unicast. + DnsServerList is NULL while DnsServerListCount is not equal to Zero. + DnsServerListCount is Zero while DnsServerListCount is not equal to NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI DNSv4 Protocol instance is not configured. + +**/ +EFI_STATUS +EFIAPI +Dns4Configure ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_CONFIG_DATA *DnsConfigData + ); + +/** + The function is used to translate the host name to host IP address. + A type A query is used to get the one or more IP addresses for this host. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] HostName Pointer to caller-supplied buffer containing Host name to be translated. + This buffer contains 16 bit characters but these are translated to ASCII for use with + DNSv4 server and there is no requirement for driver to support non-ASCII Unicode characters. + @param[in] Token Pointer to the caller-allocated completion token to return at the completion of the process to translate host name to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is.NULL + HostName is NULL + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + +**/ +EFI_STATUS +EFIAPI +Dns4HostNameToIp ( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + The function is used to translate the host address to host name. + A type PTR query is used to get the primary name of the host. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] IpAddress IP address. + @param[in] Token Pointer to the caller-allocated completion used token to translate host address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +Dns4IpToHostName ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_IPv4_ADDRESS IpAddress, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + This function retrieves arbitrary information from the DNS. + The caller supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. + All RR content (e.g., Ttl) was returned. + The caller need parse the returned RR to get required information. This function is optional. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the caller-allocated completion token to retrieve arbitrary information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_ALREADY_STARTED This Token is being used in another DNS session. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested QType is not supported + +**/ +EFI_STATUS +EFIAPI +Dns4GeneralLookUp ( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + This function is used to add/delete/modify DNS cache entry. + DNS cache can be normally dynamically updated after the DNS resolve succeeds. + This function provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param[in] Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is not TRUE. + +**/ +EFI_STATUS +EFIAPI +Dns4UpdateDnsCache ( + IN EFI_DNS4_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry + ); + +/** + This function can be used by network drivers and applications to increase the rate that data packets are moved between + the communications device and the transmit and receive queues. In some systems, the periodic timer event in the managed + network driver may not poll the underlying communications device fast enough to transmit and/or receive all data packets + without missing incoming packets or dropping outgoing packets. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +EFI_STATUS +EFIAPI +Dns4Poll ( + IN EFI_DNS4_PROTOCOL *This + ); + +/** + This function is used to abort a pending resolution request. + After calling this function, Token.Status will be set to EFI_ABORTED and then Token. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by EFI_DNS4_PROTOCOL.HostNameToIp(), + EFI_DNS4_PROTOCOL.IpToHostName() or EFI_DNS4_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS operation was not found in the transmit queue. + It was either completed or was not issued by HostNameToIp(), IpToHostName() or GeneralLookup(). + +**/ +EFI_STATUS +EFIAPI +Dns4Cancel ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + + +/** + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[out] DnsModeData Pointer to the caller-allocated storage for the EFI_DNS6_MODE_DATA structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data is + available because this instance has not been configured. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + +**/ +EFI_STATUS +EFIAPI +Dns6GetModeData ( + IN EFI_DNS6_PROTOCOL *This, + OUT EFI_DNS6_MODE_DATA *DnsModeData + ); + +/** + The function is used to set and change the configuration data for this EFI DNSv6 Protocol driver instance. + Reset the DNS instance if DnsConfigData is NULL. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DnsConfigData Pointer to the configuration data structure. + All associated storage to be allocated and released by caller. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not a valid unicast. + DnsServerList is NULL while DnsServerListCount is not equal to Zero. + DnsServerListCount is Zero while DnsServerList is not equal to NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI DNSv6 Protocol instance is not configured. + +**/ +EFI_STATUS +EFIAPI +Dns6Configure ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_CONFIG_DATA *DnsConfigData + ); + +/** + The function is used to translate the host name to host IP address. + A type AAAA query is used to get the one or more IPv6 addresses for this host. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] HostName Pointer to caller-supplied buffer containing Host name to be translated. + This buffer contains 16 bit characters but these are translated to ASCII for use with + DNSv4 server and there is no requirement for driver to support non-ASCII Unicode characters. + @param[in] Token Pointer to the caller-allocated completion token to return at the completion of the process to translate host name to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is.NULL + HostName is NULL + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + +**/ +EFI_STATUS +EFIAPI +Dns6HostNameToIp ( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + The function is used to translate the host address to host name. + A type PTR query is used to get the primary name of the host. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] IpAddress IP address. + @param[in] Token Pointer to the caller-allocated completion used token to translate host address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +Dns6IpToHostName ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_IPv6_ADDRESS IpAddress, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + This function retrieves arbitrary information from the DNS. + The caller supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. + All RR content (e.g., Ttl) was returned. + The caller need parse the returned RR to get required information. This function is optional. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the caller-allocated completion token to retrieve arbitrary information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested QType is not supported + +**/ +EFI_STATUS +EFIAPI +Dns6GeneralLookUp ( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + This function is used to add/delete/modify DNS cache entry. + DNS cache can be normally dynamically updated after the DNS resolve succeeds. + This function provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param[in] Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is not TRUE. + +**/ +EFI_STATUS +EFIAPI +Dns6UpdateDnsCache ( + IN EFI_DNS6_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry + ); + +/** + This function can be used by network drivers and applications to increase the rate that data packets are moved between + the communications device and the transmit and receive queues. In some systems, the periodic timer event in the managed + network driver may not poll the underlying communications device fast enough to transmit and/or receive all data packets + without missing incoming packets or dropping outgoing packets. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +EFI_STATUS +EFIAPI +Dns6Poll ( + IN EFI_DNS6_PROTOCOL *This + ); + +/** + This function is used to abort a pending resolution request. + After calling this function, Token.Status will be set to EFI_ABORTED and then Token. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by EFI_DNS6_PROTOCOL.HostNameToIp(), + EFI_DNS6_PROTOCOL.IpToHostName() or EFI_DNS6_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS operation was not found in the transmit queue. + It was either completed or was not issued by HostNameToIp(), IpToHostName() or GeneralLookup(). + +**/ +EFI_STATUS +EFIAPI +Dns6Cancel ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +#endif diff --git a/NetworkPkg/DnsDxe/DnsProtocol.c b/NetworkPkg/DnsDxe/DnsProtocol.c new file mode 100644 index 0000000000..eafa92984c --- /dev/null +++ b/NetworkPkg/DnsDxe/DnsProtocol.c @@ -0,0 +1,1344 @@ +/** @file +Implementation of EFI_DNS4_PROTOCOL and EFI_DNS6_PROTOCOL interfaces. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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_DNS4_PROTOCOL mDns4Protocol = { + Dns4GetModeData, + Dns4Configure, + Dns4HostNameToIp, + Dns4IpToHostName, + Dns4GeneralLookUp, + Dns4UpdateDnsCache, + Dns4Poll, + Dns4Cancel +}; + +EFI_DNS6_PROTOCOL mDns6Protocol = { + Dns6GetModeData, + Dns6Configure, + Dns6HostNameToIp, + Dns6IpToHostName, + Dns6GeneralLookUp, + Dns6UpdateDnsCache, + Dns6Poll, + Dns6Cancel +}; + +/** + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[out] DnsModeData Pointer to the caller-allocated storage for the EFI_DNS4_MODE_DATA structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data is + available because this instance has not been configured. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + +**/ +EFI_STATUS +EFIAPI +Dns4GetModeData ( + IN EFI_DNS4_PROTOCOL *This, + OUT EFI_DNS4_MODE_DATA *DnsModeData + ) +{ + DNS_INSTANCE *Instance; + + EFI_TPL OldTpl; + + UINTN Index; + + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + DNS4_SERVER_IP *ServerItem; + EFI_IPv4_ADDRESS *ServerList; + DNS4_CACHE *CacheItem; + EFI_DNS4_CACHE_ENTRY *CacheList; + EFI_STATUS Status; + + ServerItem = NULL; + ServerList = NULL; + CacheItem = NULL; + CacheList = NULL; + Status = EFI_SUCCESS; + + + if ((This == NULL) || (DnsModeData == NULL)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This); + if (Instance->State == DNS_STATE_UNCONFIGED) { + gBS->RestoreTPL (OldTpl); + return EFI_NOT_STARTED; + } + + ZeroMem (DnsModeData, sizeof (EFI_DNS4_MODE_DATA)); + + // + // Get the current configuration data of this instance. + // + Status = Dns4CopyConfigure (&DnsModeData->DnsConfigData, &Instance->Dns4CfgData); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + return Status; + } + + // + // Get the DnsServerCount and DnsServerList + // + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4ServerList) { + Index++; + } + DnsModeData->DnsServerCount = (UINT32) Index; + ServerList = AllocatePool (sizeof (EFI_IPv4_ADDRESS) * DnsModeData->DnsServerCount); + ASSERT (ServerList != NULL); + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4ServerList) { + ServerItem = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink); + CopyMem (ServerList + Index, &ServerItem->Dns4ServerIp, sizeof (EFI_IPv4_ADDRESS)); + Index++; + } + DnsModeData->DnsServerList = ServerList; + + // + // Get the DnsCacheCount and DnsCacheList + // + Index =0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) { + Index++; + } + DnsModeData->DnsCacheCount = (UINT32) Index; + CacheList = AllocatePool (sizeof (EFI_DNS4_CACHE_ENTRY) * DnsModeData->DnsCacheCount); + ASSERT (CacheList != NULL); + Index =0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) { + CacheItem = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + CopyMem (CacheList + Index, &CacheItem->DnsCache, sizeof (EFI_DNS4_CACHE_ENTRY)); + Index++; + } + DnsModeData->DnsCacheList = CacheList; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +/** + This function is used to configure DNS configuration data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DnsConfigData Pointer to caller-allocated buffer containing EFI_DNS4_CONFIG_DATA structure. + If NULL, the driver will reinitialize the protocol instance to the unconfigured state. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not a valid unicast. + DnsServerList is NULL while DnsServerListCount is not equal to Zero. + DnsServerListCount is Zero while DnsServerListCount is not equal to NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI DNSv4 Protocol instance is not configured. + +**/ +EFI_STATUS +EFIAPI +Dns4Configure ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_CONFIG_DATA *DnsConfigData + ) +{ + EFI_STATUS Status; + DNS_INSTANCE *Instance; + + EFI_TPL OldTpl; + IP4_ADDR Ip; + IP4_ADDR Netmask; + + UINT32 ServerListCount; + EFI_IPv4_ADDRESS *ServerList; + + Status = EFI_SUCCESS; + ServerList = NULL; + + if (This == NULL || + (DnsConfigData != NULL && ((DnsConfigData->DnsServerListCount != 0 && DnsConfigData->DnsServerList == NULL) || + (DnsConfigData->DnsServerListCount == 0 && DnsConfigData->DnsServerList != NULL)))) { + return EFI_INVALID_PARAMETER; + } + + if (DnsConfigData != NULL && DnsConfigData->Protocol != DNS_PROTOCOL_UDP) { + return EFI_UNSUPPORTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This); + + if (DnsConfigData == NULL) { + ZeroMem (&Instance->SessionDnsServer, sizeof (EFI_IP_ADDRESS)); + + // + // Reset the Instance if ConfigData is NULL + // + if (!NetMapIsEmpty(&Instance->Dns4TxTokens)) { + Dns4InstanceCancelToken(Instance, NULL); + } + + Instance->MaxRetry = 0; + + if (Instance->UdpIo != NULL){ + UdpIoCleanIo (Instance->UdpIo); + } + + if (Instance->Dns4CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns4CfgData.DnsServerList); + } + ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA)); + + Instance->State = DNS_STATE_UNCONFIGED; + } else { + // + // Configure the parameters for new operation. + // + CopyMem (&Ip, &DnsConfigData->StationIp, sizeof (IP4_ADDR)); + CopyMem (&Netmask, &DnsConfigData->SubnetMask, sizeof (IP4_ADDR)); + + Ip = NTOHL (Ip); + Netmask = NTOHL (Netmask); + + if (!DnsConfigData->UseDefaultSetting && + ((!IP4_IS_VALID_NETMASK (Netmask) || !NetIp4IsUnicast (Ip, Netmask)))) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = Dns4CopyConfigure (&Instance->Dns4CfgData, DnsConfigData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (DnsConfigData->DnsServerListCount == 0 || DnsConfigData->DnsServerList == NULL) { + gBS->RestoreTPL (OldTpl); + + // + // The DNS instance will retrieve DNS server from DHCP Server + // + Status = GetDns4ServerFromDhcp4 ( + Instance, + &ServerListCount, + &ServerList + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT(ServerList != NULL); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + CopyMem (&Instance->SessionDnsServer.v4, &ServerList[0], sizeof (EFI_IPv4_ADDRESS)); + } else { + CopyMem (&Instance->SessionDnsServer.v4, &DnsConfigData->DnsServerList[0], sizeof (EFI_IPv4_ADDRESS)); + } + + // + // Config UDP + // + Status = Dns4ConfigUdp (Instance, Instance->UdpIo); + if (EFI_ERROR (Status)) { + if (Instance->Dns4CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns4CfgData.DnsServerList); + } + goto ON_EXIT; + } + + // + // Add configured DNS server used by this instance to ServerList. + // + Status = AddDns4ServerIp (&mDriverData->Dns4ServerList, Instance->SessionDnsServer.v4); + if (EFI_ERROR (Status)) { + if (Instance->Dns4CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns4CfgData.DnsServerList); + } + goto ON_EXIT; + } + + Instance->State = DNS_STATE_CONFIGED; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is used to translate the host name to host IP address. + A type A query is used to get the one or more IP addresses for this host. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] HostName Pointer to caller-supplied buffer containing Host name to be translated. + This buffer contains 16 bit characters but these are translated to ASCII for use with + DNSv4 server and there is no requirement for driver to support non-ASCII Unicode characters. + @param[in] Token Pointer to the caller-allocated completion token to return at the completion of the process to translate host name to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is.NULL + HostName is NULL + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + +**/ +EFI_STATUS +EFIAPI +Dns4HostNameToIp ( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + + DNS_INSTANCE *Instance; + + EFI_DNS4_CONFIG_DATA *ConfigData; + + UINTN Index; + DNS4_CACHE *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + DNS4_TOKEN_ENTRY *TokenEntry; + NET_BUF *Packet; + + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + Item = NULL; + TokenEntry = NULL; + Packet = NULL; + + // + // Validate the parameters + // + if ((This == NULL) || (HostName == NULL) || Token == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This); + + ConfigData = &(Instance->Dns4CfgData); + + Instance->MaxRetry = ConfigData->RetryCount; + + Token->Status = EFI_NOT_READY; + Token->RetryCount = 0; + Token->RetryInterval = ConfigData->RetryInterval; + + if (Instance->State != DNS_STATE_CONFIGED) { + Status = EFI_NOT_STARTED; + goto ON_EXIT; + } + + // + // Check the MaxRetry and RetryInterval values. + // + if (Instance->MaxRetry == 0) { + Instance->MaxRetry = DNS_DEFAULT_RETRY; + } + + if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) { + Token->RetryInterval = DNS_DEFAULT_TIMEOUT; + } + + // + // Check cache + // + if (ConfigData->EnableDnsCache) { + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + if (StrCmp (HostName, Item->DnsCache.HostName) == 0) { + Index++; + } + } + + if (Index != 0) { + Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA)); + if (Token->RspData.H2AData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Token->RspData.H2AData->IpCount = (UINT32)Index; + Token->RspData.H2AData->IpList = AllocatePool (sizeof (EFI_IPv4_ADDRESS) * Index); + if (Token->RspData.H2AData->IpList == NULL) { + if (Token->RspData.H2AData != NULL) { + FreePool (Token->RspData.H2AData); + } + + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink); + if ((UINT32)Index < Token->RspData.H2AData->IpCount && StrCmp (HostName, Item->DnsCache.HostName) == 0) { + CopyMem ((Token->RspData.H2AData->IpList) + Index, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)); + Index++; + } + } + + Token->Status = EFI_SUCCESS; + + if (Token->Event != NULL) { + gBS->SignalEvent (Token->Event); + DispatchDpc (); + } + + Status = Token->Status; + goto ON_EXIT; + } + } + + // + // Construct DNS TokenEntry. + // + TokenEntry = AllocateZeroPool (sizeof(DNS4_TOKEN_ENTRY)); + if (TokenEntry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + TokenEntry->PacketToLive = Token->RetryInterval; + TokenEntry->QueryHostName = HostName; + TokenEntry->Token = Token; + + // + // Construct DNS Query Packet. + // + Status = ConstructDNSQueryIp (Instance, TokenEntry->QueryHostName, DNS_TYPE_A, &Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + goto ON_EXIT; + } + + // + // Save the token into the Dns4TxTokens map. + // + Status = NetMapInsertTail (&Instance->Dns4TxTokens, TokenEntry, Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + NetbufFree (Packet); + + goto ON_EXIT; + } + + // + // Dns Query Ip + // + Status = DoDnsQuery (Instance, Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + NetbufFree (Packet); + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is used to translate the host address to host name. + A type PTR query is used to get the primary name of the host. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] IpAddress IP address. + @param[in] Token Pointer to the caller-allocated completion used token to translate host address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +Dns4IpToHostName ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_IPv4_ADDRESS IpAddress, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function retrieves arbitrary information from the DNS. + The caller supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. + All RR content (e.g., Ttl) was returned. + The caller need parse the returned RR to get required information. This function is optional. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the caller-allocated completion token to retrieve arbitrary information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_ALREADY_STARTED This Token is being used in another DNS session. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested QType is not supported + +**/ +EFI_STATUS +EFIAPI +Dns4GeneralLookUp ( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function is used to add/delete/modify DNS cache entry. + DNS cache can be normally dynamically updated after the DNS resolve succeeds. + This function provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param[in] Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is not TRUE. + +**/ +EFI_STATUS +EFIAPI +Dns4UpdateDnsCache ( + IN EFI_DNS4_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + + if (DnsCacheEntry.HostName == NULL || DnsCacheEntry.IpAddress == NULL || DnsCacheEntry.Timeout == 0) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Update Dns4Cache here. + // + Status = UpdateDns4Cache (&mDriverData->Dns4CacheList, DeleteFlag, Override, DnsCacheEntry); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + This function can be used by network drivers and applications to increase the rate that data packets are moved between + the communications device and the transmit and receive queues. In some systems, the periodic timer event in the managed + network driver may not poll the underlying communications device fast enough to transmit and/or receive all data packets + without missing incoming packets or dropping outgoing packets. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +EFI_STATUS +EFIAPI +Dns4Poll ( + IN EFI_DNS4_PROTOCOL *This + ) +{ + DNS_INSTANCE *Instance; + EFI_UDP4_PROTOCOL *Udp; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This); + + if (Instance->State == DNS_STATE_UNCONFIGED) { + return EFI_NOT_STARTED; + } else if (Instance->State == DNS_STATE_DESTROY) { + return EFI_DEVICE_ERROR; + } + + Udp = Instance->UdpIo->Protocol.Udp4; + + return Udp->Poll (Udp); +} + +/** + This function is used to abort a pending resolution request. + After calling this function, Token.Status will be set to EFI_ABORTED and then Token. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by EFI_DNS4_PROTOCOL.HostNameToIp(), + EFI_DNS4_PROTOCOL.IpToHostName() or EFI_DNS4_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS operation was not found in the transmit queue. + It was either completed or was not issued by HostNameToIp(), IpToHostName() or GeneralLookup(). + +**/ +EFI_STATUS +EFIAPI +Dns4Cancel ( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + DNS_INSTANCE *Instance; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This); + + if (Instance->State == DNS_STATE_UNCONFIGED) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Cancle the tokens specified by Token for this instance. + // + Status = Dns4InstanceCancelToken (Instance, Token); + + // + // Dispatch the DPC queued by the NotifyFunction of the canceled token's events. + // + DispatchDpc (); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[out] DnsModeData Pointer to the caller-allocated storage for the EFI_DNS6_MODE_DATA structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data is + available because this instance has not been configured. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + +**/ +EFI_STATUS +EFIAPI +Dns6GetModeData ( + IN EFI_DNS6_PROTOCOL *This, + OUT EFI_DNS6_MODE_DATA *DnsModeData + ) +{ + DNS_INSTANCE *Instance; + + EFI_TPL OldTpl; + + UINTN Index; + + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + DNS6_SERVER_IP *ServerItem; + EFI_IPv6_ADDRESS *ServerList; + DNS6_CACHE *CacheItem; + EFI_DNS6_CACHE_ENTRY *CacheList; + EFI_STATUS Status; + + ServerItem = NULL; + ServerList = NULL; + CacheItem = NULL; + CacheList = NULL; + Status = EFI_SUCCESS; + + if ((This == NULL) || (DnsModeData == NULL)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This); + if (Instance->State == DNS_STATE_UNCONFIGED) { + gBS->RestoreTPL (OldTpl); + return EFI_NOT_STARTED; + } + + ZeroMem (DnsModeData, sizeof (EFI_DNS6_MODE_DATA)); + + // + // Get the current configuration data of this instance. + // + Status = Dns6CopyConfigure(&DnsModeData->DnsConfigData, &Instance->Dns6CfgData); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + return Status; + } + + // + // Get the DnsServerCount and DnsServerList + // + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6ServerList) { + Index++; + } + DnsModeData->DnsServerCount = (UINT32) Index; + ServerList = AllocatePool (sizeof(EFI_IPv6_ADDRESS) * DnsModeData->DnsServerCount); + ASSERT (ServerList != NULL); + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6ServerList) { + ServerItem = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink); + CopyMem (ServerList + Index, &ServerItem->Dns6ServerIp, sizeof (EFI_IPv6_ADDRESS)); + Index++; + } + DnsModeData->DnsServerList = ServerList; + + // + // Get the DnsCacheCount and DnsCacheList + // + Index =0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) { + Index++; + } + DnsModeData->DnsCacheCount = (UINT32) Index; + CacheList = AllocatePool (sizeof(EFI_DNS6_CACHE_ENTRY) * DnsModeData->DnsCacheCount); + ASSERT (CacheList != NULL); + Index =0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) { + CacheItem = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + CopyMem (CacheList + Index, &CacheItem->DnsCache, sizeof (EFI_DNS6_CACHE_ENTRY)); + Index++; + } + DnsModeData->DnsCacheList = CacheList; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +/** + The function is used to set and change the configuration data for this EFI DNSv6 Protocol driver instance. + Reset the DNS instance if DnsConfigData is NULL. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DnsConfigData Pointer to the configuration data structure. + All associated storage to be allocated and released by caller. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not a valid unicast. + DnsServerList is NULL while DnsServerListCount is not equal to Zero. + DnsServerListCount is Zero while DnsServerList is not equal to NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI DNSv6 Protocol instance is not configured. + +**/ +EFI_STATUS +EFIAPI +Dns6Configure ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_CONFIG_DATA *DnsConfigData + ) +{ + EFI_STATUS Status; + DNS_INSTANCE *Instance; + + EFI_TPL OldTpl; + + UINT32 ServerListCount; + EFI_IPv6_ADDRESS *ServerList; + + Status = EFI_SUCCESS; + ServerList = NULL; + + if (This == NULL || + (DnsConfigData != NULL && ((DnsConfigData->DnsServerCount != 0 && DnsConfigData->DnsServerList == NULL) || + (DnsConfigData->DnsServerCount == 0 && DnsConfigData->DnsServerList != NULL)))) { + return EFI_INVALID_PARAMETER; + } + + if (DnsConfigData != NULL && DnsConfigData->Protocol != DNS_PROTOCOL_UDP) { + return EFI_UNSUPPORTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This); + + if (DnsConfigData == NULL) { + ZeroMem (&Instance->SessionDnsServer, sizeof (EFI_IP_ADDRESS)); + + // + // Reset the Instance if ConfigData is NULL + // + if (!NetMapIsEmpty(&Instance->Dns6TxTokens)) { + Dns6InstanceCancelToken(Instance, NULL); + } + + Instance->MaxRetry = 0; + + if (Instance->UdpIo != NULL){ + UdpIoCleanIo (Instance->UdpIo); + } + + if (Instance->Dns6CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns6CfgData.DnsServerList); + } + ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA)); + + Instance->State = DNS_STATE_UNCONFIGED; + } else { + // + // Configure the parameters for new operation. + // + if (!NetIp6IsValidUnicast (&DnsConfigData->StationIp)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = Dns6CopyConfigure (&Instance->Dns6CfgData, DnsConfigData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (DnsConfigData->DnsServerCount == 0 || DnsConfigData->DnsServerList == NULL) { + gBS->RestoreTPL (OldTpl); + + // + //The DNS instance will retrieve DNS server from DHCP Server. + // + Status = GetDns6ServerFromDhcp6 ( + Instance->Service->ImageHandle, + Instance->Service->ControllerHandle, + &ServerListCount, + &ServerList + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + ASSERT(ServerList != NULL); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + CopyMem (&Instance->SessionDnsServer.v6, &ServerList[0], sizeof (EFI_IPv6_ADDRESS)); + } else { + CopyMem (&Instance->SessionDnsServer.v6, &DnsConfigData->DnsServerList[0], sizeof (EFI_IPv6_ADDRESS)); + } + + // + // Config UDP + // + Status = Dns6ConfigUdp (Instance, Instance->UdpIo); + if (EFI_ERROR (Status)) { + if (Instance->Dns6CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns6CfgData.DnsServerList); + } + goto ON_EXIT; + } + + // + // Add configured DNS server used by this instance to ServerList. + // + Status = AddDns6ServerIp (&mDriverData->Dns6ServerList, Instance->SessionDnsServer.v6); + if (EFI_ERROR (Status)) { + if (Instance->Dns6CfgData.DnsServerList != NULL) { + FreePool (Instance->Dns6CfgData.DnsServerList); + } + goto ON_EXIT; + } + + Instance->State = DNS_STATE_CONFIGED; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is used to translate the host name to host IP address. + A type AAAA query is used to get the one or more IPv6 addresses for this host. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] HostName Pointer to caller-supplied buffer containing Host name to be translated. + This buffer contains 16 bit characters but these are translated to ASCII for use with + DNSv4 server and there is no requirement for driver to support non-ASCII Unicode characters. + @param[in] Token Pointer to the caller-allocated completion token to return at the completion of the process to translate host name to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is.NULL + HostName is NULL + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + +**/ +EFI_STATUS +EFIAPI +Dns6HostNameToIp ( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + + DNS_INSTANCE *Instance; + + EFI_DNS6_CONFIG_DATA *ConfigData; + + UINTN Index; + DNS6_CACHE *Item; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + + DNS6_TOKEN_ENTRY *TokenEntry; + NET_BUF *Packet; + + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + Item = NULL; + TokenEntry = NULL; + Packet = NULL; + + // + // Validate the parameters + // + if ((This == NULL) || (HostName == NULL) || Token == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This); + + ConfigData = &(Instance->Dns6CfgData); + + Instance->MaxRetry = ConfigData->RetryCount; + + Token->Status = EFI_NOT_READY; + Token->RetryCount = 0; + Token->RetryInterval = ConfigData->RetryInterval; + + if (Instance->State != DNS_STATE_CONFIGED) { + Status = EFI_NOT_STARTED; + goto ON_EXIT; + } + + // + // Check the MaxRetry and RetryInterval values. + // + if (Instance->MaxRetry == 0) { + Instance->MaxRetry = DNS_DEFAULT_RETRY; + } + + if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) { + Token->RetryInterval = DNS_DEFAULT_TIMEOUT; + } + + // + // Check cache + // + if (ConfigData->EnableDnsCache) { + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + if (StrCmp (HostName, Item->DnsCache.HostName) == 0) { + Index++; + } + } + + if (Index != 0) { + Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA)); + if (Token->RspData.H2AData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Token->RspData.H2AData->IpCount = (UINT32)Index; + Token->RspData.H2AData->IpList = AllocatePool (sizeof (EFI_IPv6_ADDRESS) * Index); + if (Token->RspData.H2AData->IpList == NULL) { + if (Token->RspData.H2AData != NULL) { + FreePool (Token->RspData.H2AData); + } + + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Index = 0; + NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) { + Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink); + if ((UINT32)Index < Token->RspData.H2AData->IpCount && StrCmp (HostName, Item->DnsCache.HostName) == 0) { + CopyMem ((Token->RspData.H2AData->IpList) + Index, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)); + Index++; + } + } + + Token->Status = EFI_SUCCESS; + + if (Token->Event != NULL) { + gBS->SignalEvent (Token->Event); + DispatchDpc (); + } + + Status = Token->Status; + goto ON_EXIT; + } + } + + // + // Construct DNS TokenEntry. + // + TokenEntry = AllocateZeroPool (sizeof (DNS6_TOKEN_ENTRY)); + if (TokenEntry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + TokenEntry->PacketToLive = Token->RetryInterval; + TokenEntry->QueryHostName = HostName; + TokenEntry->Token = Token; + + // + // Construct DNS Query Packet. + // + Status = ConstructDNSQueryIp (Instance, TokenEntry->QueryHostName, DNS_TYPE_AAAA, &Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + goto ON_EXIT; + } + + // + // Save the token into the Dns6TxTokens map. + // + Status = NetMapInsertTail (&Instance->Dns6TxTokens, TokenEntry, Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + NetbufFree (Packet); + + goto ON_EXIT; + } + + // + // Dns Query Ip + // + Status = DoDnsQuery (Instance, Packet); + if (EFI_ERROR (Status)) { + if (TokenEntry != NULL) { + FreePool (TokenEntry); + } + + NetbufFree (Packet); + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is used to translate the host address to host name. + A type PTR query is used to get the primary name of the host. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] IpAddress IP address. + @param[in] Token Pointer to the caller-allocated completion used token to translate host address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +Dns6IpToHostName ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_IPv6_ADDRESS IpAddress, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function retrieves arbitrary information from the DNS. + The caller supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. + All RR content (e.g., Ttl) was returned. + The caller need parse the returned RR to get required information. This function is optional. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the caller-allocated completion token to retrieve arbitrary information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_INVALID_PARAMETER This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested QType is not supported + +**/ +EFI_STATUS +EFIAPI +Dns6GeneralLookUp ( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function is used to add/delete/modify DNS cache entry. + DNS cache can be normally dynamically updated after the DNS resolve succeeds. + This function provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the DNS Cache. + If TRUE, this function will delete matching DNS Cache entry. + @param[in] Override If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. + If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is not TRUE. + +**/ +EFI_STATUS +EFIAPI +Dns6UpdateDnsCache ( + IN EFI_DNS6_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + + if (DnsCacheEntry.HostName == NULL || DnsCacheEntry.IpAddress == NULL || DnsCacheEntry.Timeout == 0) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Update Dns6Cache here. + // + Status = UpdateDns6Cache (&mDriverData->Dns6CacheList, DeleteFlag, Override, DnsCacheEntry); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + This function can be used by network drivers and applications to increase the rate that data packets are moved between + the communications device and the transmit and receive queues. In some systems, the periodic timer event in the managed + network driver may not poll the underlying communications device fast enough to transmit and/or receive all data packets + without missing incoming packets or dropping outgoing packets. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +EFI_STATUS +EFIAPI +Dns6Poll ( + IN EFI_DNS6_PROTOCOL *This + ) +{ + DNS_INSTANCE *Instance; + EFI_UDP6_PROTOCOL *Udp; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This); + + if (Instance->State == DNS_STATE_UNCONFIGED) { + return EFI_NOT_STARTED; + } else if (Instance->State == DNS_STATE_DESTROY) { + return EFI_DEVICE_ERROR; + } + + Udp = Instance->UdpIo->Protocol.Udp6; + + return Udp->Poll (Udp); +} + +/** + This function is used to abort a pending resolution request. + After calling this function, Token.Status will be set to EFI_ABORTED and then Token. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by EFI_DNS6_PROTOCOL.HostNameToIp(), + EFI_DNS6_PROTOCOL.IpToHostName() or EFI_DNS6_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS operation was not found in the transmit queue. + It was either completed or was not issued by HostNameToIp(), IpToHostName() or GeneralLookup(). + +**/ +EFI_STATUS +EFIAPI +Dns6Cancel ( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + DNS_INSTANCE *Instance; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This); + + if (Instance->State == DNS_STATE_UNCONFIGED) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Cancle the tokens specified by Token for this instance. + // + Status = Dns6InstanceCancelToken (Instance, Token); + + // + // Dispatch the DPC queued by the NotifyFunction of the canceled token's events. + // + DispatchDpc (); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + -- 2.39.2