summaryrefslogtreecommitdiff
path: root/NetworkPkg
diff options
context:
space:
mode:
authorjiaxinwu <jiaxin.wu@intel.com>2015-07-07 08:22:03 +0000
committerjiaxinwu <jiaxinwu@Edk2>2015-07-07 08:22:03 +0000
commit99c048ef4aca44589d519946ee6a6c890ad9123b (patch)
treeda327aeb9a98a8e7e5ac1ceaf774efce2d76d4ec /NetworkPkg
parent1f6729ffe98095107ce82e67a4a0209674601a90 (diff)
downloadedk2-platforms-99c048ef4aca44589d519946ee6a6c890ad9123b.tar.xz
NetworkPkg: Add DNS feature support over IPv4 and IPv6.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: jiaxinwu <jiaxin.wu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17854 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'NetworkPkg')
-rw-r--r--NetworkPkg/DnsDxe/ComponentName.c443
-rw-r--r--NetworkPkg/DnsDxe/DnsDhcp.c762
-rw-r--r--NetworkPkg/DnsDxe/DnsDhcp.h145
-rw-r--r--NetworkPkg/DnsDxe/DnsDriver.c1554
-rw-r--r--NetworkPkg/DnsDxe/DnsDriver.h606
-rw-r--r--NetworkPkg/DnsDxe/DnsDxe.inf76
-rw-r--r--NetworkPkg/DnsDxe/DnsImpl.c1875
-rw-r--r--NetworkPkg/DnsDxe/DnsImpl.h1139
-rw-r--r--NetworkPkg/DnsDxe/DnsProtocol.c1344
9 files changed, 7944 insertions, 0 deletions
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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DnsImpl.h"
+
+//
+// EFI 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.<BR>
+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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DnsImpl.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gDns4DriverBinding = {
+ Dns4DriverBindingSupported,
+ Dns4DriverBindingStart,
+ Dns4DriverBindingStop,
+ DNS_VERSION,
+ NULL,
+ NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gDns6DriverBinding = {
+ Dns6DriverBindingSupported,
+ Dns6DriverBindingStart,
+ Dns6DriverBindingStop,
+ DNS_VERSION,
+ NULL,
+ NULL
+};
+
+EFI_SERVICE_BINDING_PROTOCOL mDns4ServiceBinding = {
+ Dns4ServiceBindingCreateChild,
+ Dns4ServiceBindingDestroyChild
+};
+
+EFI_SERVICE_BINDING_PROTOCOL mDns6ServiceBinding = {
+ Dns6ServiceBindingCreateChild,
+ Dns6ServiceBindingDestroyChild
+};
+
+DNS_DRIVER_DATA *mDriverData = NULL;
+
+/**
+ Destroy the DNS instance and recycle the resources.
+
+ @param[in] Instance The pointer to the DNS instance.
+
+**/
+VOID
+DnsDestroyInstance (
+ IN DNS_INSTANCE *Instance
+ )
+{
+ ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA));
+
+ ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA));
+
+ if (!NetMapIsEmpty (&Instance->Dns4TxTokens)) {
+ Dns4InstanceCancelToken (Instance, NULL);
+ }
+
+ if (!NetMapIsEmpty (&Instance->Dns6TxTokens)) {
+ Dns6InstanceCancelToken (Instance, NULL);
+ }
+
+ if (Instance->UdpIo!= NULL) {
+ UdpIoFreeIo (Instance->UdpIo);
+ }
+
+ FreePool (Instance);
+}
+
+/**
+ Create the DNS instance and initialize it.
+
+ @param[in] Service The pointer to the DNS service.
+ @param[out] Instance The pointer to the DNS instance.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+ @retval EFI_SUCCESS The DNS instance is created.
+
+**/
+EFI_STATUS
+DnsCreateInstance (
+ IN DNS_SERVICE *Service,
+ OUT DNS_INSTANCE **Instance
+ )
+{
+ DNS_INSTANCE *DnsIns;
+
+ *Instance = NULL;
+
+ DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE));
+ if (DnsIns == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DnsIns->Signature = DNS_INSTANCE_SIGNATURE;
+ InitializeListHead (&DnsIns->Link);
+ DnsIns->State = DNS_STATE_UNCONFIGED;
+ DnsIns->InDestroy = FALSE;
+ DnsIns->Service = Service;
+
+ if (Service->IpVersion == IP_VERSION_4) {
+ CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4));
+ NetMapInit (&DnsIns->Dns4TxTokens);
+ } else {
+ CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6));
+ NetMapInit (&DnsIns->Dns6TxTokens);
+ }
+
+ DnsIns->UdpIo = UdpIoCreateIo (
+ Service->ControllerHandle, /// NicHandle
+ Service->ImageHandle,
+ DnsConfigNullUdp,
+ Service->IpVersion,
+ DnsIns
+ );
+ if (DnsIns->UdpIo == NULL) {
+ FreePool (DnsIns);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Instance = DnsIns;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function which provided by user to remove one node in NetDestroyLinkList process.
+
+ @param[in] Entry The entry to be removed.
+ @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
+
+ @retval EFI_SUCCESS The entry has been removed successfully.
+ @retval Others Fail to remove the entry.
+
+**/
+EFI_STATUS
+EFIAPI
+DnsDestroyChildEntryInHandleBuffer (
+ IN LIST_ENTRY *Entry,
+ IN VOID *Context
+ )
+{
+ DNS_INSTANCE *Instance;
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ UINTN NumberOfChildren;
+ EFI_HANDLE *ChildHandleBuffer;
+
+ if (Entry == NULL || Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = NET_LIST_USER_STRUCT_S (Entry, DNS_INSTANCE, Link, DNS_INSTANCE_SIGNATURE);
+ ServiceBinding = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
+ NumberOfChildren = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
+ ChildHandleBuffer = ((DNS_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
+
+ if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) {
+ return EFI_SUCCESS;
+ }
+
+ return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
+}
+
+/**
+ Config a NULL UDP that is used to keep the connection between UDP and DNS.
+
+ Just leave the Udp child unconfigured. When UDP is unloaded,
+ DNS will be informed with DriverBinding Stop.
+
+ @param UdpIo The UDP_IO to configure
+ @param Context The opaque parameter to the callback
+
+ @retval EFI_SUCCESS It always return EFI_SUCCESS directly.
+
+**/
+EFI_STATUS
+EFIAPI
+DnsConfigNullUdp (
+ IN UDP_IO *UdpIo,
+ IN VOID *Context
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Release all the resource used the DNS service binding instance.
+
+ @param DnsSb The Dns service binding instance.
+
+**/
+VOID
+DnsDestroyService (
+ IN DNS_SERVICE *DnsSb
+ )
+{
+ UdpIoFreeIo (DnsSb->ConnectUdp);
+
+ if (DnsSb->TimerToGetMap != NULL){
+ gBS->CloseEvent (DnsSb->TimerToGetMap);
+ }
+
+ if (DnsSb->Timer != NULL){
+ gBS->CloseEvent (DnsSb->Timer);
+ }
+
+ FreePool (DnsSb);
+}
+
+/**
+ Create then initialize a Dns service binding instance.
+
+ @param Controller The controller to install the DNS service
+ binding on
+ @param Image The driver binding image of the DNS driver
+ @param IpVersion IpVersion for this service
+ @param Service The variable to receive the created service
+ binding instance.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance.
+ @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
+ connection with UDP.
+ @retval EFI_SUCCESS The service instance is created for the
+ controller.
+
+**/
+EFI_STATUS
+DnsCreateService (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Image,
+ IN UINT8 IpVersion,
+ OUT DNS_SERVICE **Service
+ )
+{
+ EFI_STATUS Status;
+ DNS_SERVICE *DnsSb;
+
+ Status = EFI_SUCCESS;
+ DnsSb = NULL;
+
+ *Service = NULL;
+
+ DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE));
+ if (DnsSb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DnsSb->Signature = DNS_SERVICE_SIGNATURE;
+
+ if (IpVersion == IP_VERSION_4) {
+ DnsSb->ServiceBinding = mDns4ServiceBinding;
+ } else {
+ DnsSb->ServiceBinding = mDns6ServiceBinding;
+ }
+
+ DnsSb->Dns4ChildrenNum = 0;
+ InitializeListHead (&DnsSb->Dns4ChildrenList);
+
+ DnsSb->Dns6ChildrenNum = 0;
+ InitializeListHead (&DnsSb->Dns6ChildrenList);
+
+ DnsSb->ControllerHandle = Controller;
+ DnsSb->ImageHandle = Image;
+
+ DnsSb->TimerToGetMap = NULL;
+
+ DnsSb->Timer = NULL;
+
+ DnsSb->IpVersion = IpVersion;
+
+ //
+ // Create the timer used to time out the procedure which is used to
+ // get the default IP address.
+ //
+ 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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DNS_DRIVER_H_
+#define _DNS_DRIVER_H_
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+
+///
+/// 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.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DnsImpl.h"
+
+/**
+ 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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DNS_IMPL_H_
+#define __EFI_DNS_IMPL_H_
+
+#include <Uefi.h>
+
+//
+// Libraries classes
+//
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DpcLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UdpIoLib.h>
+
+//
+// UEFI Driver Model Protocols
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/ComponentName.h>
+
+#include <Protocol/Udp4.h>
+#include <Protocol/Dhcp4.h>
+#include <Protocol/Dns4.h>
+
+#include <Protocol/Udp6.h>
+#include <Protocol/Dhcp6.h>
+#include <Protocol/Dns6.h>
+
+#include <Protocol/Ip4Config2.h>
+
+#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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DnsImpl.h"
+
+EFI_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;
+}
+