/* DnsDxe.c -- DNS protocol DXE driver
*
* Source: AmiNetworkPkg/UefiNetworkStack/Common/DnsDxe/
* DnsDriver.c - _ModuleEntryPoint, driver binding, service binding
* DnsProtocol.c - EFI_DNS4_PROTOCOL and EFI_DNS6_PROTOCOL methods
* DnsImpl.c - Packet parsing, DNS query building, response processing
*
* Reconstructed from DnsDxe.efi (Index 0144, SHA256 61d65b3b4799...)
*/
#include "DnsDxe.h"
/* ========================================================================
* Global variable definitions
* ======================================================================== */
EFI_HANDLE ImageHandle = NULL;
EFI_SYSTEM_TABLE *SystemTable = NULL;
EFI_BOOT_SERVICES *BootServices = NULL;
EFI_RUNTIME_SERVICES *RuntimeServices = NULL;
/* DPC event handle -- used to queue deferred DNS response processing.
* Located via gBS->LocateProtocol(&gEfiDpcProtocolGuid, 0, &DpcEvent). */
VOID *DpcEvent = NULL;
/* DNS Timer event handle (periodic, 1-second interval) */
EFI_EVENT DnsTimer = NULL;
/* DNS cache + retry management state.
* qword_BF90 points to a DNS_CACHE_MANAGER structure:
* 0x00: TimerEvent (EFI_EVENT)
* 0x08: CacheList (LIST_ENTRY head for IPv4 cache entries)
* 0x18: ...
* 0x28: ServerList (LIST_ENTRY head for IPv4 server info)
* 0x38: ...
* 0x40: CacheList6 (LIST_ENTRY head for IPv6 cache entries)
* 0x50: ...
* 0x58: ServerList6 (LIST_ENTRY head for IPv6 server info)
* 0x68: ...
*/
UINTN DnsCacheManager = 0;
/* Debug output protocol handle */
VOID *DebugOutProtocol = NULL;
/* HOB list pointer for system table retrieval */
VOID *HobList = NULL;
/* The driver binding protocol handles */
EFI_HANDLE Dns4DriverBindingHandle = NULL;
EFI_HANDLE Dns6DriverBindingHandle = NULL;
/* Known RR type mapping table -- used during DNS response validation
* to verify that received record type values are recognized. */
UINT32 DnsKnownRrTypes[33] = { 0 };
/* ========================================================================
* Forward declarations for internally-used functions
* (mapped from sub_XXXX to meaningful names)
* ======================================================================== */
/* --- Utility / memory wrappers --- */
static EFI_STATUS EFIAPI DxeAllocatePool(UINTN Size, VOID **Buffer);
static VOID *AllocateZeroPool(UINTN Size);
static VOID *AllocateCopyPool(VOID *Dst, VOID *Src, UINTN Size);
static VOID ZeroMem(VOID *Buffer, UINTN Size);
static EFI_STATUS FreePoolAligned(VOID *Buffer);
/* --- Linked-list helpers --- */
static VOID RemoveEntryList(LIST_ENTRY *Entry);
static BOOLEAN IsListEmpty(CONST LIST_ENTRY *Entry);
static VOID InsertHeadList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry);
static VOID InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry);
/* --- ASSERT / debug output --- */
static VOID DebugAssert(CONST CHAR8 *FileName, UINTN LineNumber,
CONST CHAR8 *Desc);
static VOID DebugPrint(UINTN ErrorLevel, CONST CHAR8 *Format, ...);
/* --- NET_MAP operations --- */
static EFI_STATUS NetMapInsert(NET_MAP *Map, INTN Key, INTN Value, VOID *Ptr);
static EFI_STATUS NetMapIterate(NET_MAP *Map, INTN (*Func)(NET_MAP_ITEM *, VOID *), VOID *Context);
static INTN NetMapGetCount(NET_MAP *Map);
static VOID NetMapCleanup(NET_MAP *Map);
/* --- NET_BUF operations --- */
static NET_BUF *NetbufFromExt(VOID *Data, UINTN Size);
static EFI_STATUS NetbufFree(NET_BUF *Nbuf);
/* --- DNS packet processing --- */
static EFI_STATUS DnsBuildPacket(DNS_INSTANCE *Instance,
CHAR16 *QueryName,
UINT16 QueryType, UINT16 QueryClass,
NET_BUF **Packet);
static EFI_STATUS DnsParseResponse(DNS_INSTANCE *Instance,
NET_BUF *Packet,
DNS4_TOKEN_ENTRY *Token4 OPTIONAL,
DNS6_TOKEN_ENTRY *Token6 OPTIONAL);
static EFI_STATUS DnsTransmitPacket(DNS_INSTANCE *Instance, NET_BUF *Packet);
/* --- Cache management --- */
static EFI_STATUS DnsCacheInsert(DNS_INSTANCE *Instance, UINTN IpVersion,
CHAR16 *HostName, VOID *Address,
UINT32 TtlValue);
static EFI_STATUS DnsCacheRemove(DNS_INSTANCE *Instance, UINTN IpVersion,
CHAR16 *Hostname);
/* --- Timer callback --- */
static VOID EFIAPI DnsTimerNotify(EFI_EVENT Event, VOID *Context);
static VOID EFIAPI DnsCacheTimerNotify(EFI_EVENT Event, VOID *Context);
static VOID EFIAPI DnsOnUdpReceive(VOID *Context, VOID *Packet);
static VOID EFIAPI DnsTransmitRetransmit(DNS_INSTANCE *Instance,
NET_BUF *Packet);
/* ========================================================================
* Module Entry Point
* Called by UEFI core when the driver is loaded.
* ======================================================================== */
EFI_STATUS
EFIAPI
ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINTN DpcHandle;
/* Save global handles */
::ImageHandle = ImageHandle;
::SystemTable = (UINTN)SystemTable;
BootServices = (UINTN)SystemTable->BootServices;
RuntimeServices = (UINTN)SystemTable->RuntimeServices;
/* Initialize HOB list for system table access */
DxeGetHobList();
/* Locate DPC protocol handle */
Status = BootServices->LocateProtocol(
&gEfiDpcProtocolGuid, 0, (VOID **)&DpcEvent);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT! (Status = %r)\n", Status));
ASSERT(!EFI_ERROR(Status));
}
/* Install driver binding protocols and service bindings */
Status = DnsDriverEntry(ImageHandle);
if (EFI_ERROR(Status)) {
return Status;
}
/* Install protocol interfaces on ImageHandle */
Status = BootServices->InstallMultipleProtocolInterfaces(
&Dns4DriverBindingHandle,
&gEfiDns4ServiceBindingProtocolGuid,
&mDns4ServiceBinding,
&gEfiComponentName2ProtocolGuid,
&mDnsComponentName,
NULL);
if (EFI_ERROR(Status)) {
BootServices->UninstallMultipleProtocolInterfaces(
ImageHandle,
&gEfiDns4ServiceBindingProtocolGuid,
&mDns4ServiceBinding,
&gEfiComponentName2ProtocolGuid,
&mDnsComponentName,
NULL);
}
return Status;
}
/* ========================================================================
* Driver Binding protocol callbacks
* ======================================================================== */
/* DNS_DRIVER_BINDING_PROTOCOL Support/Start/Stop */
EFI_STATUS
EFIAPI
Dns4DriverBindingSupported(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
VOID *Interface;
Status = BootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp4ServiceBindingProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (!EFI_ERROR(Status)) {
BootServices->CloseProtocol(
ControllerHandle,
&gEfiUdp4ServiceBindingProtocolGuid,
This->DriverBindingHandle,
ControllerHandle);
return EFI_SUCCESS;
}
Status = BootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp4ProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (!EFI_ERROR(Status)) {
BootServices->CloseProtocol(
ControllerHandle,
&gEfiUdp4ProtocolGuid,
This->DriverBindingHandle,
ControllerHandle);
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Dns4DriverBindingStart(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
return DnsCreateService(ControllerHandle, 4);
}
EFI_STATUS
EFIAPI
Dns4DriverBindingStop(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
return DnsDestroyService(ControllerHandle, 4);
}
EFI_STATUS
EFIAPI
Dns6DriverBindingSupported(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
VOID *Interface;
Status = BootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp6ServiceBindingProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (!EFI_ERROR(Status)) {
BootServices->CloseProtocol(
ControllerHandle,
&gEfiUdp6ServiceBindingProtocolGuid,
This->DriverBindingHandle,
ControllerHandle);
return EFI_SUCCESS;
}
Status = BootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp6ProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (!EFI_ERROR(Status)) {
BootServices->CloseProtocol(
ControllerHandle,
&gEfiUdp6ProtocolGuid,
This->DriverBindingHandle,
ControllerHandle);
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Dns6DriverBindingStart(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
return DnsCreateService(ControllerHandle, 6);
}
EFI_STATUS
EFIAPI
Dns6DriverBindingStop(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
return DnsDestroyService(ControllerHandle, 6);
}
/* ========================================================================
* DnsCreateService -- Create DNS service binding for given IP version
* (sub_7A0)
*
* Allocates DNS_SERVICE_BINDING_PRIVATE structure, opens UDP protocol,
* creates timer event for cache expiry, and creates the DPC timer.
* ======================================================================== */
EFI_STATUS
DnsCreateService(
IN EFI_HANDLE ControllerHandle,
IN UINT8 IpVersion /* 4 or 6 */
)
{
EFI_STATUS Status;
DNS_SERVICE_BINDING *Service;
EFI_GUID *UdpServiceGuid;
EFI_GUID *DnsSbGuid;
EFI_HANDLE UdpHandle;
UINTN UdpVersion;
UDP_IO *UdpIo;
*ServiceBinding = 0;
Service = AllocateZeroPool(sizeof(DNS_SERVICE_BINDING));
if (Service == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Service->Signature = DNS_SB_SIGNATURE;
if (IpVersion == 4) {
UdpServiceGuid = &gEfiUdp4ServiceBindingProtocolGuid;
UdpVersion = 4;
} else {
UdpServiceGuid = &gEfiUdp6ServiceBindingProtocolGuid;
UdpVersion = 6;
}
/* Open UDP service binding on controller */
Status = BootServices->OpenProtocol(
ControllerHandle,
UdpServiceGuid,
(VOID **)&UdpHandle,
ControllerHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR(Status)) {
goto Error;
}
/* Create UDP IO */
UdpIo = UdpIoCreateIo(
ControllerHandle,
Service->DriverBindingHandle,
UdpVersion,
0);
if (UdpIo == NULL) {
goto Error;
}
Service->UdpIo = UdpIo;
/* Create a periodic timer event for cache expiry */
Status = BootServices->CreateEvent(
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
DnsCacheTimerNotify,
Service,
&Service->TimerEvent);
if (EFI_ERROR(Status)) {
UdpIoDestroyIo(UdpIo);
goto Error;
}
/* Set 1-second periodic timer */
Status = BootServices->SetTimer(
Service->TimerEvent,
TimerPeriodic,
10000000);
if (EFI_ERROR(Status)) {
BootServices->CloseEvent(Service->TimerEvent);
UdpIoDestroyIo(UdpIo);
goto Error;
}
Service->IpVersion = IpVersion;
Service->RefCount = 0;
Service->ControllerHandle = ControllerHandle;
*ServiceBinding = Service;
return EFI_SUCCESS;
Error:
FreePoolAligned(Service);
return EFI_OUT_OF_RESOURCES;
}
/* ========================================================================
* DnsDestroyService -- Tear down DNS service binding
* (sub_51C)
* ======================================================================== */
EFI_STATUS
DnsDestroyService(
IN EFI_HANDLE ControllerHandle,
IN UINT8 IpVersion
)
{
DNS_SERVICE_BINDING *Service;
/* Locate the service instance from controller handle */
Service = DnsLookupService(ControllerHandle, IpVersion);
if (Service == NULL) {
return EFI_NOT_FOUND;
}
/* Clean up any pending transactions (IPv4 and/or IPv6) */
if (!NetMapIsEmpty(&Service->Dns4TxTokens)) {
DnsCleanupTokenMap(&Service->Dns4TxTokens,
DNS4_TOKEN_ENTRY_FROM_MAP_ITEM,
EFI_ABORTED);
}
if (!NetMapIsEmpty(&Service->Dns6TxTokens)) {
DnsCleanupTokenMap(&Service->Dns6TxTokens,
DNS6_TOKEN_ENTRY_FROM_MAP_ITEM,
EFI_ABORTED);
}
/* Close timer event */
if (Service->DnsTimerEvent != NULL) {
BootServices->CloseEvent(Service->DnsTimerEvent);
}
/* Destroy UDP IO */
if (Service->UdpIo != NULL) {
UdpIoDestroyIo(Service->UdpIo);
}
/* Free the service structure itself */
FreePoolAligned(Service);
return EFI_SUCCESS;
}
/* ========================================================================
* DnsDriverEntry -- Top-level driver entry called from entry point
* Installs the driver binding protocol on ImageHandle for both IPv4 and IPv6.
* (sub_BD8)
* ======================================================================== */
EFI_STATUS
DnsDriverEntry(
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
/* Install DNSv4 driver binding */
Status = EfiLibInstallDriverBindingComponentName2(
ImageHandle,
SystemTable,
&mDns4DriverBinding,
ImageHandle);
if (EFI_ERROR(Status)) {
return Status;
}
/* Install DNSv6 driver binding */
Status = EfiLibInstallDriverBindingComponentName2(
ImageHandle,
SystemTable,
&mDns6DriverBinding,
NULL);
if (EFI_ERROR(Status)) {
/* On failure, uninstall the DNSv4 binding + component names */
BootServices->UninstallMultipleProtocolInterfaces(
ImageHandle,
&gEfiDns4ServiceBindingProtocolGuid,
&mDns4DriverBinding,
&gEfiComponentName2ProtocolGuid,
&mDnsComponentName,
&gEfiComponentNameProtocolGuid,
&mDnsComponentName,
NULL);
return Status;
}
/* Allocate cache manager state for DnsCacheManager (qword_BF90) */
DnsCacheManager = (UINTN)AllocateZeroPool(sizeof(DNS_CACHE_MANAGER));
if (DnsCacheManager == 0) {
return EFI_OUT_OF_RESOURCES;
}
/* Create a DPC-related timer for deferred response processing */
Status = BootServices->CreateEvent(
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
DnsPeriodicTimer,
NULL,
(EFI_EVENT *)DnsCacheManager);
if (EFI_ERROR(Status)) {
goto Error;
}
Status = BootServices->SetTimer(
*(EFI_EVENT *)DnsCacheManager,
TimerPeriodic,
10000000);
if (EFI_ERROR(Status)) {
goto Error;
}
/* Initialize cache lists */
InitializeListHead((LIST_ENTRY *)(DnsCacheManager + 8));
InitializeListHead((LIST_ENTRY *)(DnsCacheManager + 24));
InitializeListHead((LIST_ENTRY *)(DnsCacheManager + 40));
InitializeListHead((LIST_ENTRY *)(DnsCacheManager + 56));
return EFI_SUCCESS;
Error:
if (*(EFI_EVENT *)DnsCacheManager != NULL) {
BootServices->CloseEvent(*(EFI_EVENT *)DnsCacheManager);
}
if (DnsCacheManager) {
FreePoolAligned((VOID *)DnsCacheManager);
DnsCacheManager = 0;
}
return Status;
}
/* ========================================================================
* DNSv4 Protocol: GetHostByName (sub_3540)
* ======================================================================== */
EFI_STATUS
EFIAPI
Dns4GetHostByName(
IN EFI_DNS4_PROTOCOL *This,
IN CHAR16 *Hostname,
OUT EFI_DNS4_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
EFI_STATUS Status;
UINTN ServerCount;
UINT32 *ServerList;
LIST_ENTRY *Entry;
DNS_CACHE_ENTRY *CacheEntry;
UINTN Index;
if (This == NULL || Hostname == NULL || Token == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance == NULL) {
return EFI_INVALID_PARAMETER;
}
/* Check if driver is started */
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
/* If already configured, return cached entry */
if (Instance->Dns4CfgData.UseDefaultSetting) {
/* Initialize the token response */
ZeroMem((VOID *)&Token->RspData, sizeof(Token->RspData));
Token->Status = EFI_NOT_READY;
if (Instance->Dns4RetryCount > 0) {
/* Attempt to look up from cache first */
ServerList = NULL;
ServerCount = Instance->Dns4CacheMap.Count;
/* Fill in server list */
Token->RspData.General.ResponseBufferSize = ServerCount * sizeof(EFI_IPv4_ADDRESS);
/* Find the entry: iterate cache map */
Entry = Instance->Dns4CacheMap.List.ForwardLink;
Index = 0;
return EFI_SUCCESS;
}
}
return EFI_DEVICE_ERROR;
}
/* ========================================================================
* DNSv4 Protocol: GetHostByAddr (sub_377C)
* ======================================================================== */
EFI_STATUS
EFIAPI
Dns4GetHostByAddr(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_IPv4_ADDRESS *IpAddress,
OUT EFI_DNS4_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
UINTN Ret;
UINTN TokenData;
UINT32 ReverseIp;
UINT32 IpCheck;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Token != NULL) {
if (Token->Event != NULL && Token->Status != NULL) {
/* Valid: have both */
} else if (Token->Event == NULL && Token->Status == NULL) {
/* Neither event nor status -- that is valid too */
} else {
return EFI_INVALID_PARAMETER;
}
if (Token->RspData.General.QueryBuffer[1] != 17) {
return EFI_UNSUPPORTED;
}
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
/* Build PTR query: reverse IP + ".in-addr.arpa" */
if (Token != NULL) {
/* Byte-swap and reverse the IP address */
ReverseIp = ((UINT32)Token->RspData.General.QueryBuffer[19] << 24) |
((UINT32)Token->RspData.General.QueryBuffer[20] << 16) |
((UINT32)Token->RspData.General.QueryBuffer[21] << 8) |
((UINT32)Token->RspData.General.QueryBuffer[22]);
/* Validate IP against known PTR types */
if (Token->RspData.General.ResponseBuffer[0] == 0) {
/* Check each byte */
UINTN i;
for (i = 0; i <= 32; i++) {
if (ReverseIp == DnsKnownRrTypes[i])
break;
}
if (ReverseIp == 0)
goto Submit;
/* Check if non-zero bits mask matches */
if (i == 31 || ...) {
Submit:
/* Submit the PTR query as host-by-name with PTR type */
Ret = DnsSubmitPacket4(Instance, Token);
if (!EFI_ERROR(Ret)) {
/* Trigger packet transmission */
Status = DnsSendQuery(Instance, TokenData, ...);
if (!EFI_ERROR(Status)) {
return EFI_SUCCESS;
}
/* Cancel if tx failed */
DnsCancelPacket4(Instance, Token);
}
}
}
}
return Ret;
}
/* ========================================================================
* DNSv4 Protocol: Poll (sub_40A4)
* ========================================================================
* Checks for received network data and processes it.
*/
EFI_STATUS
EFIAPI
Dns4Poll(
IN EFI_DNS4_PROTOCOL *This
)
{
DNS_INSTANCE *Instance;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
if (Instance->Mode == 2) {
return EFI_ACCESS_DENIED;
}
/* Call UdpIo's Poll function to drain the receive queue */
return UdpIoPoll(Instance->UdpIo);
}
/* ========================================================================
* DNSv4 Protocol: Cancel (sub_4138)
* ========================================================================
* Cancels a pending DNS query token.
*/
EFI_STATUS
EFIAPI
Dns4Cancel(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_DNS4_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
/* Remove from TxTokens map and signal completion */
return DnsCancelToken(&Instance->Dns4TxTokens,
DNS4_TOKEN_ENTRY_FROM_MAP_ITEM,
Token);
}
/* ========================================================================
* DNSv4 Protocol: GetConfigData (sub_34AC)
* ========================================================================
* Returns current DNS configuration data (server list, cache names).
*/
EFI_STATUS
EFIAPI
Dns4GetConfigData(
IN EFI_DNS4_PROTOCOL *This,
OUT EFI_DNS4_CONFIG_DATA *ConfigData
)
{
DNS_INSTANCE *Instance;
if (This == NULL || ConfigData == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
/* Fill config data from Instance */
CopyMem(ConfigData, &Instance->Dns4CfgData, sizeof(EFI_DNS4_CONFIG_DATA));
ConfigData->StationIp = Instance->Dns4CfgData.StationIp;
ConfigData->LocalPort = Instance->Dns4CfgData.LocalPort;
ConfigData->RetryCount = Instance->Dns4CfgData.RetryCount;
ConfigData->RetryInterval = Instance->Dns4CfgData.RetryInterval;
return EFI_SUCCESS;
}
/* ========================================================================
* DNSv4 Protocol: SetConfigData (sub_7A0)
* ========================================================================
* Sets DNS configuration and creates UDP IO for the new config.
*/
EFI_STATUS
EFIAPI
Dns4SetConfigData(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_DNS4_CONFIG_DATA *ConfigData
)
{
return DnsSetConfigData(This, ConfigData, 4);
}
/* ========================================================================
* DNSv4 Protocol: GetServerList (sub_3540 reused)
* ========================================================================
* Returns the list of DNS server addresses.
*/
EFI_STATUS
EFIAPI
Dns4GetServerList(
IN EFI_DNS4_PROTOCOL *This,
IN OUT UINTN *ServerCount,
OUT EFI_IPv4_ADDRESS *ServerList
)
{
DNS_INSTANCE *Instance;
LIST_ENTRY *Entry;
UINTN Count;
UINT32 *Addrs;
if (This == NULL || ServerCount == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS4_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
if (Instance->Mode == 0) {
Instance = (VOID *)((UINT8 *)Instance - 24);
}
if (Instance->Dns4ChildrenList.ForwardLink == NULL) {
return EFI_NOT_READY;
}
/* Count servers */
Count = 0;
for (Entry = Instance->Dns4CacheMap.List.ForwardLink;
Entry != &Instance->Dns4CacheMap.List;
Entry = Entry->ForwardLink) {
Count++;
}
*ServerCount = Count;
/* Allocate and fill server addresses */
Addrs = AllocateZeroPool(sizeof(UINT32) * Count);
if (Addrs == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Entry = Instance->Dns4CacheMap.List.ForwardLink;
Count = 0;
while (Entry != &Instance->Dns4CacheMap.List &&
Count < *ServerCount) {
Addrs[Count] = ((DNS_CACHE_ENTRY *)Entry)->TtlValue;
Count++;
Entry = Entry->ForwardLink;
}
*ServerList = (EFI_IPv4_ADDRESS *)Addrs;
return EFI_SUCCESS;
}
/* ========================================================================
* DNSv4 Protocol: GetHostName / SetHostName stubs (sub_4000)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns4GetHostName(
IN EFI_DNS4_PROTOCOL *This,
OUT CHAR16 *Hostname,
IN OUT UINTN *HostnameSize
)
{
return DnsGetHostName(This, Hostname, HostnameSize, 4);
}
EFI_STATUS
EFIAPI
Dns4SetHostName(
IN EFI_DNS4_PROTOCOL *This,
IN CHAR16 *Hostname
)
{
return DnsSetHostName(This, Hostname, 4);
}
/* ========================================================================
* DNSv6 Protocol: GetHostByName (sub_41E8)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6GetHostByName(
IN EFI_DNS6_PROTOCOL *This,
IN CHAR16 *Hostname,
OUT EFI_DNS6_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
EFI_STATUS Status;
UINTN ServerCount;
EFI_IPv6_ADDRESS *ServerList;
LIST_ENTRY *Entry;
UINTN Index;
if (This == NULL || Hostname == NULL || Token == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS6_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
if (!Instance->Dns6CfgData.UseDefaultSetting) {
/* Use cache server list */
ServerCount = Instance->Dns6CacheMap.Count;
/* Allocate reply data */
Token->RspData.General.ResponseBuffer =
AllocateZeroPool(16 * ServerCount);
}
return EFI_SUCCESS;
}
/* ========================================================================
* DNSv6 Protocol: GetHostByAddr (sub_4424)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6GetHostByAddr(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_IPv6_ADDRESS *IpAddress,
OUT EFI_DNS6_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
UINTN Ret;
UINT8 Index;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Token != NULL) {
if (Token->RspData.General.ResponseBufferSize != 0) {
if (Token->RspData.General.ResponseBuffer == NULL) {
/* Both zero = valid for no-buffer mode */
goto CheckProtocol;
}
}
CheckProtocol:
if (Token->RspData.General.QueryBuffer[1] != 17) {
return EFI_UNSUPPORTED;
}
}
Instance = DNS_INSTANCE_FROM_DNS6_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
/* Validate IPv6 address fields from the token */
if (Token != NULL) {
/* Check that the address is non-zero */
Index = 0;
while (Index < 16 && Token->RspData.General.QueryBuffer[2 + Index] == 0) {
Index++;
}
if (Index >= 15) {
return EFI_INVALID_PARAMETER;
}
/* Submit PTR query for IPv6 reverse lookup */
/* Reuse DnsSubmitPacket4/6 infrastructure */
Token->Status = EFI_NOT_READY;
Ret = DnsBuildQuery6(Instance, IpAddress, Token);
if (!EFI_ERROR(Ret)) {
DnsSendQuery6(Instance, Token);
}
} else {
/* Called with no token - just clean up */
DnsCancelAll6(Instance);
Ret = EFI_SUCCESS;
}
return Ret;
}
/* ========================================================================
* DNSv6 Protocol: Poll (sub_4C60)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6Poll(
IN EFI_DNS6_PROTOCOL *This
)
{
/* Same as Dns4Poll but for IPv6 */
UINT8 Version;
if (DnsCheckMode(This, 6) <= 0) {
return EFI_NOT_STARTED;
}
/* Drain the receive queue -- poll the UDPv6 IO */
{
DNS_INSTANCE *Instance = DNS_INSTANCE_FROM_DNS6_PROTOCOL(This);
if (Instance->UdpIo != NULL) {
return UdpIoPoll(Instance->UdpIo);
}
}
return EFI_DEVICE_ERROR;
}
/* ========================================================================
* DNSv6 Protocol: Cancel (sub_4D04)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6Cancel(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_DNS6_COMPLETION_TOKEN *Token
)
{
DNS_INSTANCE *Instance;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS6_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
return Dns6CancelToken(Instance, Token);
}
/* ========================================================================
* DNSv6 Protocol: GetConfigData (sub_4D98)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6GetConfigData(
IN EFI_DNS6_PROTOCOL *This,
OUT EFI_DNS6_CONFIG_DATA *ConfigData
)
{
DNS_INSTANCE *Instance;
if (This == NULL || ConfigData == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DNS_INSTANCE_FROM_DNS6_PROTOCOL(This);
if (Instance->Mode == 0) {
return EFI_NOT_STARTED;
}
CopyMem(ConfigData, &Instance->Dns6CfgData, sizeof(EFI_DNS6_CONFIG_DATA));
return EFI_SUCCESS;
}
/* ========================================================================
* DNSv6 Protocol: SetConfigData (sub_4E48)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6SetConfigData(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_DNS6_CONFIG_DATA *ConfigData
)
{
return DnsSetConfigData(This, ConfigData, 6);
}
/* ========================================================================
* DNSv6 Protocol: GetHostName / SetHostName (sub_4E7C, sub_4F70)
* ========================================================================
*/
EFI_STATUS
EFIAPI
Dns6GetHostName(
IN EFI_DNS6_PROTOCOL *This,
OUT CHAR16 *Hostname,
IN OUT UINTN *HostnameSize
)
{
/* TODO: return the configured DNSv6 hostname */
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Dns6SetHostName(
IN EFI_DNS6_PROTOCOL *This,
IN CHAR16 *Hostname
)
{
/* TODO: set the DNSv6 hostname */
return EFI_UNSUPPORTED;
}
/* ========================================================================
* DNS query building (sub_313C)
* ========================================================================
* Constructs a DNS query packet on the wire for the given query name,
* query type (A/AAAA/PTR), and query class (IN).
*/
EFI_STATUS
DnsBuildQuery(
IN DNS_INSTANCE *Instance,
IN CHAR8 *QueryName,
IN UINT16 QueryType,
IN UINT16 QueryClass,
OUT NET_BUF **Packet
)
{
DNS_HEADER *DnsHeader;
UINT8 *PacketData;
UINT8 *NamePtr;
UINTN NameLen;
UINTN TotalSize;
UINT16 Id;
EFI_STATUS Status;
PacketData = AllocateZeroPool(512);
if (PacketData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
/* Generate a random identifier */
Id = (UINT16)((1103515245 * (UINT32)DnsRandom() + 12345) % 0xFFFFFFFF);
/* Build DNS header */
DnsHeader = (DNS_HEADER *)PacketData;
DnsHeader->Identification = SwapBytes16(Id);
DnsHeader->Flags = SwapBytes16(0x0100); /* Standard query, RD=1 */
DnsHeader->Questions = SwapBytes16(1);
/* Encode the query name as DNS label sequence */
NamePtr = PacketData + sizeof(DNS_HEADER);
NameLen = AsciiStrLen(QueryName) + 2; /* +2 for root terminator */
DnsNameToLabels(NamePtr, QueryName);
/* Question footer */
NamePtr += NameLen;
*(UINT16 *)NamePtr = SwapBytes16(QueryType);
*(UINT16 *)(NamePtr + 2) = SwapBytes16(QueryClass);
TotalSize = (UINTN)(NamePtr + 4 - PacketData);
/* Convert to NetBuf */
*Packet = NetbufFromExt(PacketData, TotalSize);
if (*Packet == NULL) {
FreePoolAligned(PacketData);
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/* ========================================================================
* Internal DNS response parsing (sub_25D0)
* ========================================================================
* Parses a received DNS response packet from the wire.
* Handles A, AAAA, CNAME, and PTR records.
*/
EFI_STATUS
DnsParseResponse(
IN DNS_INSTANCE *Instance,
IN NET_BUF *Packet,
IN DNS4_TOKEN_ENTRY *Token4 OPTIONAL,
IN DNS6_TOKEN_ENTRY *Token6 OPTIONAL
)
{
DNS_HEADER *DnsHeader;
UINT8 *RxData;
UINTN RxDataLen;
UINT16 Questions;
UINT16 Answers;
UINT16 AuthorityRRs;
UINT16 AdditionalRRs;
UINT8 *Cursor;
UINTN Offset;
UINTN AnswerIndex;
UINT16 RType;
UINT16 RClass;
UINT32 RTtl;
UINT16 RdLength;
UINT8 *RData;
UINT8 IpVersion;
BOOLEAN Done;
EFI_STATUS Status;
Done = FALSE;
Status = EFI_SUCCESS;
RxData = (UINT8 *)NetbufGetData(Packet);
RxDataLen = NetbufGetSize(Packet);
IpVersion = Instance->IpVersion;
if (RxDataLen <= 12) {
*Done = TRUE;
return EFI_UNSUPPORTED;
}
/* Byte-swap the DNS header fields */
DnsHeader = (DNS_HEADER *)RxData;
DnsHeader->Identification = SwapBytes16(DnsHeader->Identification);
DnsHeader->Flags = SwapBytes16(DnsHeader->Flags);
DnsHeader->Questions = SwapBytes16(DnsHeader->Questions);
DnsHeader->Answers = SwapBytes16(DnsHeader->Answers);
DnsHeader->Authority = SwapBytes16(DnsHeader->Authority);
DnsHeader->Additional = SwapBytes16(DnsHeader->Additional);
Questions = DnsHeader->Questions;
Answers = DnsHeader->Answers;
AuthorityRRs = DnsHeader->Authority;
AdditionalRRs = DnsHeader->Additional;
/* Validate: this is a response with no error */
if ((DnsHeader->Flags & 0x800F) != 0x8000) {
*Done = TRUE;
return EFI_PROTOCOL_ERROR;
}
/* Skip questions */
if (Questions > 1) {
*Done = TRUE;
return EFI_PROTOCOL_ERROR;
}
/* Process answer records */
AnswerIndex = 0;
while (AnswerIndex < Answers) {
/* Skip compressed name */
Cursor = RxData + 12;
/* Parse RR header */
if (Cursor[0] & 0xC0) {
Cursor += 2;
} else {
while (*Cursor != 0) Cursor++;
Cursor++;
}
/* Byte-swap RR header fields */
RType = SwapBytes16(*(UINT16 *)Cursor);
RClass = SwapBytes16(*(UINT16 *)(Cursor + 2));
RTtl = SwapBytes32(*(UINT32 *)(Cursor + 4));
RdLength = SwapBytes16(*(UINT16 *)(Cursor + 8));
RData = Cursor + 10;
if ((IpVersion == 4 && Token4 &&
Token4->IsHostByName && RType == DNS_TYPE_A) ||
(IpVersion == 6 && Token6 &&
Token6->IsHostByName && RType == DNS_TYPE_AAAA)) {
/* Save address */
if (IpVersion == 4) {
if (RdLength >= 4) {
CopyMem(Token4->RcvData, RData, 4);
}
} else {
if (RdLength >= 16) {
CopyMem(Token6->RcvData, RData, 16);
}
}
}
/* Insert into cache */
if (RType == DNS_TYPE_A && Token4 != NULL && Token4->IsHostByName) {
DnsCacheInsert(Instance, 4, Token4->HostName, Cursor + 10, RTtl);
}
/* Update cache TTL for subsequent records */
Cursor += RdLength + 10;
AnswerIndex++;
}
*Done = TRUE;
return EFI_SUCCESS;
}
/* ========================================================================
* DnsSubmitPacket4 -- Submit a DNSv4 query packet for transmission
* (sub_3E14 shared for 4&6)
* ======================================================================== */
EFI_STATUS
DnsSubmitPacket4(
IN DNS_INSTANCE *Instance,
IN CHAR16 *Hostname,
IN UINT16 QueryType,
IN UINT16 QueryClass,
IN EFI_DNS4_COMPLETION_TOKEN *Token
)
{
DNS4_TOKEN_ENTRY *TokenEntry;
NET_BUF *Packet;
EFI_STATUS Status;
if (Instance == NULL || Hostname == NULL || Token == NULL) {
return EFI_INVALID_PARAMETER;
}
TokenEntry = AllocateZeroPool(sizeof(DNS4_TOKEN_ENTRY));
if (TokenEntry == NULL) {
return EFI_OUT_OF_RESOURCES;
}
TokenEntry->RetryCount = Token->RspData.General.ResponseBufferSize;
TokenEntry->IsHostByName = (QueryType == DNS_TYPE_A);
TokenEntry->Token = Token;
TokenEntry->HostName = Hostname;
/* Build and transmit the query */
Status = DnsBuildQuery(Instance, Hostname, QueryType, QueryClass, &Packet);
if (EFI_ERROR(Status)) {
FreePoolAligned(TokenEntry);
return Status;
}
/* Insert into Tx token map */
Status = NetMapInsert(&Instance->Dns4TxTokens, 0, 0, TokenEntry);
if (EFI_ERROR(Status)) {
NetbufFree(Packet);
FreePoolAligned(TokenEntry);
return Status;
}
/* Transmit packet */
Status = DnsTransmit(Instance, Packet);
if (EFI_ERROR(Status)) {
NetMapIterate(&Instance->Dns4TxTokens, NULL, TokenEntry);
NetbufFree(Packet);
FreePoolAligned(TokenEntry);
return Status;
}
return EFI_SUCCESS;
}
/* ========================================================================
* Periodic timer callback (sub_32F4)
* ========================================================================
* Fires every second. Decrements retry timers for pending token entries.
* When a retry count reaches zero, the token is aborted and a timeout
* status is signaled.
*/
VOID
EFIAPI
DnsPeriodicTimerNotify(
IN EFI_EVENT Event,
IN VOID *Context
)
{
DNS_SERVICE_BINDING *Service = (DNS_SERVICE_BINDING *)Context;
LIST_ENTRY *Entry4, *Entry6, *Next4, *Next6;
DNS4_TOKEN_ENTRY *Token4;
DNS6_TOKEN_ENTRY *Token6;
if (Service == NULL) {
return;
}
if (Service->IpVersion == 4) {
/* Walk the IPv4 token map */
Entry4 = Service->Dns4TxTokens.List.ForwardLink;
while (Entry4 != &Service->Dns4TxTokens.List) {
DNS4_TOKEN_ENTRY *T4;
Next4 = Entry4->ForwardLink;
T4 = DNS4_TOKEN_ENTRY_FROM_MAP_ITEM(Entry4);
if (T4->RetryTimer > 0) {
T4->RetryTimer--;
if (T4->RetryTimer == 0) {
T4->RetryCount++;
if (T4->RetryCount >= T4->TimeoutValue) {
/* Abort this entry */
NetMapIterate(&Service->Dns4TxTokens, NULL, T4);
/* Signal completion with timeout */
T4->Token->Status = EFI_TIMEOUT;
BootServices->SignalEvent(T4->Token->Event);
if (Service->UdpIo != NULL) {
UdpIoRecycle(Service->UdpIo);
}
/* Done with this entry */
NetMapIterate(&Service->Dns4TxTokens, NULL, T4);
} else {
/* Retransmit */
NetMapIterate(&Service->Dns4TxTokens, NULL, T4);
T4->RetryTimer = T4->TimeoutValue;
}
}
}
Entry4 = Next4;
}
} else {
/* Walk the IPv6 token map */
Entry6 = Service->Dns6TxTokens.List.ForwardLink;
while (Entry6 != &Service->Dns6TxTokens.List) {
DNS6_TOKEN_ENTRY *T6;
Next6 = Entry6->ForwardLink;
T6 = DNS6_TOKEN_ENTRY_FROM_MAP_ITEM(Entry6);
if (T6->RetryTimer > 0) {
T6->RetryTimer--;
if (T6->RetryTimer == 0) {
T6->RetryCount++;
if (T6->RetryCount >= T6->TimeoutValue) {
/* Abort */
T6->Token->Status = EFI_TIMEOUT;
BootServices->SignalEvent(T6->Token->Event);
if (Service->UdpIo != NULL) {
UdpIoRecycle(Service->UdpIo);
}
} else {
/* Retransmit */
T6->RetryTimer = T6->TimeoutValue;
}
}
}
Entry6 = Next6;
}
}
}
/* ========================================================================
* Cache manager periodic timer (sub_34AC)
* ========================================================================
* Decrements TTL for every cache entry (both IPv4 and IPv6).
* When TTL hits zero, the entry is freed.
*/
VOID
EFIAPI
DnsCacheTimerNotify(
IN EFI_EVENT Event,
IN VOID *Context
)
{
DNS_CACHE_MANAGER *CacheMgr = (DNS_CACHE_MANAGER *)Context;
LIST_ENTRY *Entry, *Next;
if (CacheMgr == NULL) {
CacheMgr = (DNS_CACHE_MANAGER *)qword_BF90;
if (CacheMgr == NULL) {
return;
}
}
/* Process IPv4 cache list */
Entry = CacheMgr->CacheList.ForwardLink;
while (Entry != &CacheMgr->CacheList) {
Next = Entry->ForwardLink;
((DNS_CACHE_ENTRY *)Entry)->TtlValue--;
if (((DNS_CACHE_ENTRY *)Entry)->TtlValue == 0) {
/* Remove from cache */
RemoveEntryList(Entry);
DnsFreeCacheEntry((DNS_CACHE_ENTRY *)Entry);
}
Entry = Next;
}
/* Process IPv6 cache list */
Entry = CacheMgr->CacheList6.ForwardLink;
while (Entry != &CacheMgr->CacheList6) {
Next = Entry->ForwardLink;
((DNS_CACHE_ENTRY *)Entry)->TtlValue--;
if (((DNS_CACHE_ENTRY *)Entry)->TtlValue == 0) {
RemoveEntryList(Entry);
DnsFreeCacheEntry((DNS_CACHE_ENTRY *)Entry);
}
Entry = Next;
}
}
/* ========================================================================
* DnsSetConfigData -- common handler for both IPv4 and IPv6
* (sub_59C body adapted)
* ========================================================================
*/
EFI_STATUS
DnsSetConfigData(
IN VOID *This,
IN VOID *ConfigData,
IN UINT8 IpVersion
)
{
DNS_INSTANCE *Instance;
DNS_SERVICE_BINDING *Service;
EFI_STATUS Status;
Instance = NULL;
/* Create new instance */
Status = DnsCreateInstance(&Instance, (UINTN)ConfigData, IpVersion);
if (EFI_ERROR(Status)) {
return Status;
}
/* Save configuration */
if (IpVersion == 4) {
CopyMem(&Instance->Dns4CfgData, ConfigData, sizeof(EFI_DNS4_CONFIG_DATA));
} else {
CopyMem(&Instance->Dns6CfgData, ConfigData, sizeof(EFI_DNS6_CONFIG_DATA));
}
/* Create UDP IO for this configuration */
Status = DnsCreateUdpIo(Instance);
if (EFI_ERROR(Status)) {
DnsDestroyInstance(Instance);
return Status;
}
return EFI_SUCCESS;
}
/* ========================================================================
* DnsTransmit -- send a DNS query packet via UDP
* (sub_30E8)
* ========================================================================
*/
EFI_STATUS
DnsTransmit(
IN DNS_INSTANCE *Instance,
IN NET_BUF *Packet
)
{
EFI_STATUS Status;
/* Check if we need to create a UDP IO first */
if (Instance->UdpIo == NULL) {
Status = DnsCreateUdpIo(Instance);
if (EFI_ERROR(Status)) {
return Status;
}
}
/* Increase reference count on packet */
Packet->RefCnt++;
/* Queue the packet for transmission */
Status = UdpIoSend(Instance->UdpIo, Packet, 0, 0);
if (EFI_ERROR(Status)) {
Packet->RefCnt--;
return Status;
}
return EFI_SUCCESS;
}
/* ========================================================================
* DnsRandom -- get a random value for DNS query IDs
* (sub_7F84)
* ========================================================================
*/
UINT32
DnsRandom(
VOID
)
{
UINT32 Value;
/* Use RTC to seed a simple LCG */
Value = (UINT32)(BootServices->GetTimer(&Value, 0) + Value);
Value = (1103515245 * Value + 12345) % 0xFFFFFFFF;
return Value;
}
/* ========================================================================
* ASSERT / debug support (sub_5E58, sub_5DD0)
* ========================================================================
*/
VOID
DebugAssert(
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Desc
)
{
/* In DEBUG builds, print assertion info and halt */
if (DebugOutProtocol != NULL) {
((VOID (*)(VOID *))DebugOutProtocol)(...);
}
/* In RELEASE builds: no-op */
return;
}
/* ========================================================================
* DnsCreateInstance -- allocates and initializes DNS instance structure
* (sub_59C)
* ========================================================================
*/
EFI_STATUS
DnsCreateInstance(
OUT DNS_INSTANCE **Instance,
IN UINTN ServiceBinding,
IN UINT8 IpVersion
)
{
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->Dns4TxTokens.List);
DnsIns->Mode = 1; /* Started */
DnsIns->IpVersion = IpVersion;
/* Initialize cache map, tx token map, server list */
if (IpVersion == 4) {
InitializeListHead(&DnsIns->Dns4CacheMap.List);
InitializeListHead(&DnsIns->Dns4ServerList);
} else {
InitializeListHead(&DnsIns->Dns6CacheMap.List);
InitializeListHead(&DnsIns->Dns6ServerList);
}
*Instance = DnsIns;
return EFI_SUCCESS;
}
/* ========================================================================
* DnsDestroyInstance -- tears down DNS instance
* ========================================================================
*/
VOID
DnsDestroyInstance(
IN DNS_INSTANCE *Instance
)
{
if (Instance == NULL) {
return;
}
/* Clean up any pending tokens */
if (!NetMapIsEmpty(&Instance->Dns4TxTokens)) {
DnsCleanupTokenMap(&Instance->Dns4TxTokens,
DNS4_TOKEN_ENTRY_FROM_MAP_ITEM,
EFI_ABORTED);
}
if (!NetMapIsEmpty(&Instance->Dns6TxTokens)) {
DnsCleanupTokenMap(&Instance->Dns6TxTokens,
DNS6_TOKEN_ENTRY_FROM_MAP_ITEM,
EFI_ABORTED);
}
/* Free the UDP IO */
if (Instance->UdpIo != NULL) {
UdpIoDestroyIo(Instance->UdpIo);
}
FreePoolAligned(Instance);
}
/* ========================================================================
* DnsNameToLabels -- convert dotted name to DNS label format
* e.g., "www.example.com" -> 3www7example3com0
* ========================================================================
*/
UINT8 *
DnsNameToLabels(
OUT UINT8 *Buf,
IN CONST CHAR8 *Name
)
{
UINT8 *Orig = Buf;
UINT8 *Label = ++Buf;
while (*Name) {
if (*Name == '.') {
/* Terminate label with its length */
*Orig = (UINT8)(Buf - Orig - 1);
Orig = Buf;
Buf++;
Name++;
} else {
*Buf++ = (UINT8)*Name++;
}
}
/* Terminate last label */
*Orig = (UINT8)(Buf - Orig - 1);
*Buf++ = 0;
return Buf;
}
/* ========================================================================
* UdpIo support - helper wrappers
* ========================================================================*/
/* UdpIoCreateIo -- creates UDP IO protocol for given version */
UDP_IO *
UdpIoCreateIo(
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE DriverHandle,
IN UINT8 UdpVersion,
IN UINT32 Flags
)
{
/* TODO: actual implementation opens Udp4 or Udp6 protocol
* on controller and wraps into UDP_IO structure */
return NULL;
}
VOID
UdpIoDestroyIo(
IN UDP_IO *UdpIo
)
{
/* TODO: close protocol and free resources */
}
EFI_STATUS
UdpIoSend(
IN UDP_IO *UdpIo,
IN NET_BUF *Packet,
IN UINTN EndPoint,
IN UINTN RemoteAddr
)
{
/* TODO: transmit NET_BUF via UDP */
return EFI_SUCCESS;
}
EFI_STATUS
UdpIoPoll(
IN UDP_IO *UdpIo
)
{
/* TODO: poll underlying UDP for receive */
return EFI_SUCCESS;
}
VOID
UdpIoRecycle(
IN UDP_IO *UdpIo
)
{
/* TODO: recycle UDP receive buffer */
}
EFI_STATUS
DnsCreateUdpIo(
IN DNS_INSTANCE *Instance
)
{
/* Called when DnsSetConfigData needs to create UDP transport */
return EFI_UNSUPPORTED;
}
/* ========================================================================
* DnsCancel -- cancel a specific token from the TX list
* ========================================================================
*/
EFI_STATUS
DnsCancelTokenMap(
IN NET_MAP *Map,
IN VOID *Token
)
{
/* Walk the map items and cancel matching token */
/* TODO: implement */
return EFI_NOT_FOUND;
}
EFI_STATUS
DnsCleanupTokenMap(
IN NET_MAP *Map,
IN VOID *TokenEntry,
IN EFI_STATUS CompletionStatus
)
{
/* Walk the map, signal tokens, remove items */
/* TODO: implement */
return EFI_SUCCESS;
}
BOOLEAN
NetMapIsEmpty(
IN NET_MAP *Map
)
{
return IsListEmpty(&Map->List);
}
/* ========================================================================
* Utility function implementations
* ======================================================================== */
static EFI_STATUS
DxeAllocatePool(
IN UINTN Size,
OUT VOID **Buffer
)
{
return BootServices->AllocatePool(EfiBootServicesData, Size, Buffer);
}
static VOID *
AllocateZeroPool(
IN UINTN Size
)
{
VOID *Buffer;
if (Size == 0) {
return NULL;
}
if (BootServices->AllocatePool(EfiBootServicesData, Size, &Buffer) !=
EFI_SUCCESS) {
return NULL;
}
ZeroMem(Buffer, Size);
return Buffer;
}
static EFI_STATUS
FreePoolAligned(
IN VOID *Buffer
)
{
return BootServices->FreePool(Buffer);
}
static VOID
ZeroMem(
IN VOID *Buffer,
IN UINTN Size
)
{
UINT8 *Ptr = (UINT8 *)Buffer;
UINTN i;
for (i = 0; i < Size; i++) {
Ptr[i] = 0;
}
}
static VOID
CopyMem(
IN VOID *Dest,
IN VOID *Source,
IN UINTN Size
)
{
UINT8 *D = (UINT8 *)Dest;
UINT8 *S = (UINT8 *)Source;
UINTN i;
for (i = 0; i < Size; i++) {
D[i] = S[i];
}
}
static BOOLEAN
IsListEmpty(
IN CONST LIST_ENTRY *Entry
)
{
return (Entry->ForwardLink == Entry);
}
static VOID
RemoveEntryList(
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink->BackLink = Entry->BackLink;
Entry->BackLink->ForwardLink = Entry->ForwardLink;
}
static VOID
InsertHeadList(
IN LIST_ENTRY *ListHead,
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink = ListHead->ForwardLink;
Entry->BackLink = ListHead;
ListHead->ForwardLink->BackLink = Entry;
ListHead->ForwardLink = Entry;
}
static VOID
InsertTailList(
IN LIST_ENTRY *ListHead,
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink = ListHead;
Entry->BackLink = ListHead->BackLink;
ListHead->BackLink->ForwardLink = Entry;
ListHead->BackLink = Entry;
}
/* SwapBytes16 */
static UINT16
SwapBytes16(
IN UINT16 Value
)
{
return (UINT16)((Value >> 8) | (Value << 8));
}
/* SwapBytes32 */
static UINT32
SwapBytes32(
IN UINT32 Value
)
{
return (Value >> 24) | ((Value >> 8) & 0xFF00) |
((Value << 8) & 0xFF0000) | (Value << 24);
}
/* CR macro based container access */
#define CR(Record, Type, Field, Signature) \
(VOID *)((UINT8 *)(Record) - OFFSET_OF(Type, Field))
/* ========================================================================
* Protocol function table definitions
* ======================================================================== */
EFI_DNS4_PROTOCOL mDns4ProtocolTemplate = {
Dns4GetHostByName, /* 0x00 GetHostByName */
Dns4GetHostByAddr, /* 0x08 GetHostByAddr */
Dns4Poll, /* 0x10 Poll */
Dns4Cancel, /* 0x18 Cancel */
Dns4GetConfigData, /* 0x20 GetConfigData */
Dns4SetConfigData, /* 0x28 SetConfigData */
Dns4GetServerList, /* 0x30 GetServerList */
Dns4GetHostName, /* 0x38 GetHostName */
Dns4SetHostName /* 0x40 SetHostName */
};
EFI_DNS6_PROTOCOL mDns6ProtocolTemplate = {
Dns6GetHostByName, /* 0x00 GetHostByName */
Dns6GetHostByAddr, /* 0x08 GetHostByAddr */
Dns6Poll, /* 0x10 Poll */
Dns6Cancel, /* 0x18 Cancel */
Dns6GetConfigData, /* 0x20 GetConfigData */
Dns6SetConfigData, /* 0x28 SetConfigData */
Dns6GetServerList, /* 0x30 GetServerList */
Dns6GetHostName, /* 0x38 GetHostName */
Dns6SetHostName /* 0x40 SetHostName */
};