/** @file | |
DnsDxe support functions implementation. | |
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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 successfully. | |
@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 successfully. | |
@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 cancel 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 cancel 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 successfully. | |
@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 successfully. | |
@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 occurred. | |
**/ | |
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 occurred. | |
**/ | |
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))) { | |
if (Ip6Mode.AddressList != NULL) { | |
FreePool (Ip6Mode.AddressList); | |
} | |
if (Ip6Mode.GroupTable != NULL) { | |
FreePool (Ip6Mode.GroupTable); | |
} | |
if (Ip6Mode.RouteTable != NULL) { | |
FreePool (Ip6Mode.RouteTable); | |
} | |
if (Ip6Mode.NeighborCache != NULL) { | |
FreePool (Ip6Mode.NeighborCache); | |
} | |
if (Ip6Mode.PrefixTable != NULL) { | |
FreePool (Ip6Mode.PrefixTable); | |
} | |
if (Ip6Mode.IcmpTypeList != NULL) { | |
FreePool (Ip6Mode.IcmpTypeList); | |
} | |
if (!Ip6Mode.IsStarted || Ip6Mode.IsConfigured) { | |
Udp->Configure (Udp, NULL); | |
if (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS) { | |
return TRUE; | |
} | |
} | |
} | |
} | |
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); | |
FreePool (Item->DnsCache.HostName); | |
FreePool (Item->DnsCache.IpAddress); | |
FreePool (Item); | |
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) { | |
FreePool (NewDnsCache); | |
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) { | |
FreePool (NewDnsCache->DnsCache.HostName); | |
FreePool (NewDnsCache); | |
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); | |
FreePool (Item->DnsCache.HostName); | |
FreePool (Item->DnsCache.IpAddress); | |
FreePool (Item); | |
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) { | |
FreePool (NewDnsCache); | |
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) { | |
FreePool (NewDnsCache->DnsCache.HostName); | |
FreePool (NewDnsCache); | |
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 Class Class 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, | |
IN UINT16 Class, | |
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); | |
ASSERT (TxString != NULL); | |
DnsHeader = (DNS_HEADER *)TxString; | |
QueryName = (CHAR8 *)(TxString + sizeof (*DnsHeader)); | |
QuerySection = (DNS_QUERY_SECTION *)(QueryName + AsciiStrLen (QueryName) + 1); | |
if ((NTOHS (DnsHeader->Identification) == Identification) && | |
(NTOHS (QuerySection->Type) == Type) && | |
(NTOHS (QuerySection->Class) == Class)) | |
{ | |
return TRUE; | |
} | |
} | |
} | |
*Item = NULL; | |
return FALSE; | |
} | |
/** | |
Parse Dns Response. | |
@param Instance The DNS instance | |
@param RxString Received buffer. | |
@param Length Received buffer length. | |
@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, | |
IN UINT32 Length, | |
OUT BOOLEAN *Completed | |
) | |
{ | |
DNS_HEADER *DnsHeader; | |
CHAR8 *QueryName; | |
UINT32 QueryNameLen; | |
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 RRCount; | |
UINT32 AnswerSectionNum; | |
UINT32 CNameTtl; | |
EFI_IPv4_ADDRESS *HostAddr4; | |
EFI_IPv6_ADDRESS *HostAddr6; | |
EFI_DNS4_CACHE_ENTRY *Dns4CacheEntry; | |
EFI_DNS6_CACHE_ENTRY *Dns6CacheEntry; | |
DNS_RESOURCE_RECORD *Dns4RR; | |
DNS6_RESOURCE_RECORD *Dns6RR; | |
EFI_STATUS Status; | |
UINT32 RemainingLength; | |
EFI_TPL OldTpl; | |
Item = NULL; | |
Dns4TokenEntry = NULL; | |
Dns6TokenEntry = NULL; | |
IpCount = 0; | |
RRCount = 0; | |
AnswerSectionNum = 0; | |
CNameTtl = 0; | |
HostAddr4 = NULL; | |
HostAddr6 = NULL; | |
Dns4CacheEntry = NULL; | |
Dns6CacheEntry = NULL; | |
Dns4RR = NULL; | |
Dns6RR = NULL; | |
*Completed = TRUE; | |
Status = EFI_SUCCESS; | |
RemainingLength = Length; | |
// | |
// Check whether the remaining packet length is available or not. | |
// | |
if (RemainingLength <= sizeof (DNS_HEADER)) { | |
*Completed = FALSE; | |
return EFI_ABORTED; | |
} else { | |
RemainingLength -= sizeof (DNS_HEADER); | |
} | |
// | |
// 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); | |
// | |
// There is always one QuestionsNum in DNS message. The capability to handle more | |
// than one requires to redesign the message format. Currently, it's not supported. | |
// | |
if (DnsHeader->QuestionsNum > 1) { | |
*Completed = FALSE; | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Get Query name | |
// | |
QueryName = (CHAR8 *)(RxString + sizeof (*DnsHeader)); | |
QueryNameLen = (UINT32)AsciiStrLen (QueryName) + 1; | |
// | |
// Check whether the remaining packet length is available or not. | |
// | |
if (RemainingLength <= QueryNameLen + sizeof (DNS_QUERY_SECTION)) { | |
*Completed = FALSE; | |
return EFI_ABORTED; | |
} else { | |
RemainingLength -= (QueryNameLen + sizeof (DNS_QUERY_SECTION)); | |
} | |
// | |
// Get query section | |
// | |
QuerySection = (DNS_QUERY_SECTION *)(QueryName + QueryNameLen); | |
QuerySection->Type = NTOHS (QuerySection->Type); | |
QuerySection->Class = NTOHS (QuerySection->Class); | |
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, | |
QuerySection->Class, | |
&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, | |
QuerySection->Class, | |
&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)) | |
{ | |
// | |
// The domain name referenced in the query does not exist. | |
// | |
if (DnsHeader->Flags.Bits.RCode == DNS_FLAGS_RCODE_NAME_ERROR) { | |
Status = EFI_NOT_FOUND; | |
} else { | |
Status = EFI_DEVICE_ERROR; | |
} | |
goto ON_COMPLETE; | |
} | |
// | |
// Do some buffer allocations. | |
// | |
if (Instance->Service->IpVersion == IP_VERSION_4) { | |
ASSERT (Dns4TokenEntry != NULL); | |
if (Dns4TokenEntry->GeneralLookUp) { | |
// | |
// It's the GeneralLookUp querying. | |
// | |
Dns4TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD)); | |
if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD)); | |
if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
} else { | |
// | |
// It's not the GeneralLookUp querying. Check the Query type. | |
// | |
if (QuerySection->Type == DNS_TYPE_A) { | |
Dns4TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS_HOST_TO_ADDR_DATA)); | |
if (Dns4TokenEntry->Token->RspData.H2AData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS)); | |
if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
} else { | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
} | |
} else { | |
ASSERT (Dns6TokenEntry != NULL); | |
if (Dns6TokenEntry->GeneralLookUp) { | |
// | |
// It's the GeneralLookUp querying. | |
// | |
Dns6TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD)); | |
if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD)); | |
if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
} else { | |
// | |
// It's not the GeneralLookUp querying. Check the Query type. | |
// | |
if (QuerySection->Type == DNS_TYPE_AAAA) { | |
Dns6TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS6_HOST_TO_ADDR_DATA)); | |
if (Dns6TokenEntry->Token->RspData.H2AData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS)); | |
if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
} else { | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
} | |
} | |
Status = EFI_NOT_FOUND; | |
// | |
// Get Answer name | |
// | |
AnswerName = (CHAR8 *)QuerySection + sizeof (*QuerySection); | |
// | |
// Processing AnswerSection. | |
// | |
while (AnswerSectionNum < DnsHeader->AnswersNum) { | |
// | |
// Check whether the remaining packet length is available or not. | |
// | |
if (RemainingLength <= sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION)) { | |
*Completed = FALSE; | |
Status = EFI_ABORTED; | |
goto ON_EXIT; | |
} else { | |
RemainingLength -= (sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION)); | |
} | |
// | |
// Answer name should be PTR, else EFI_UNSUPPORTED returned. | |
// | |
if ((*(UINT8 *)AnswerName & 0xC0) != 0xC0) { | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
// | |
// 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); | |
// | |
// Check whether the remaining packet length is available or not. | |
// | |
if (RemainingLength < AnswerSection->DataLength) { | |
*Completed = FALSE; | |
Status = EFI_ABORTED; | |
goto ON_EXIT; | |
} else { | |
RemainingLength -= AnswerSection->DataLength; | |
} | |
// | |
// Check whether it's the GeneralLookUp querying. | |
// | |
if ((Instance->Service->IpVersion == IP_VERSION_4) && Dns4TokenEntry->GeneralLookUp) { | |
Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList; | |
AnswerData = (UINT8 *)AnswerSection + sizeof (*AnswerSection); | |
// | |
// Fill the ResourceRecord. | |
// | |
Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1); | |
if (Dns4RR[RRCount].QName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName)); | |
Dns4RR[RRCount].QType = AnswerSection->Type; | |
Dns4RR[RRCount].QClass = AnswerSection->Class; | |
Dns4RR[RRCount].TTL = AnswerSection->Ttl; | |
Dns4RR[RRCount].DataLength = AnswerSection->DataLength; | |
Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength); | |
if (Dns4RR[RRCount].RData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength); | |
RRCount++; | |
Status = EFI_SUCCESS; | |
} else if ((Instance->Service->IpVersion == IP_VERSION_6) && Dns6TokenEntry->GeneralLookUp) { | |
Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList; | |
AnswerData = (UINT8 *)AnswerSection + sizeof (*AnswerSection); | |
// | |
// Fill the ResourceRecord. | |
// | |
Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1); | |
if (Dns6RR[RRCount].QName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName)); | |
Dns6RR[RRCount].QType = AnswerSection->Type; | |
Dns6RR[RRCount].QClass = AnswerSection->Class; | |
Dns6RR[RRCount].TTL = AnswerSection->Ttl; | |
Dns6RR[RRCount].DataLength = AnswerSection->DataLength; | |
Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength); | |
if (Dns6RR[RRCount].RData == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength); | |
RRCount++; | |
Status = EFI_SUCCESS; | |
} else { | |
// | |
// It's not the GeneralLookUp querying. | |
// Check the Query type, parse the response packet. | |
// | |
switch (AnswerSection->Type) { | |
case DNS_TYPE_A: | |
// | |
// This is address entry, get Data. | |
// | |
ASSERT (Dns4TokenEntry != NULL); | |
if (AnswerSection->DataLength != 4) { | |
Status = EFI_ABORTED; | |
goto ON_EXIT; | |
} | |
HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList; | |
AnswerData = (UINT8 *)AnswerSection + sizeof (*AnswerSection); | |
CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS)); | |
// | |
// Allocate new CacheEntry pool to update DNS cache dynamically. | |
// | |
Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY)); | |
if (Dns4CacheEntry == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen (Dns4TokenEntry->QueryHostName) + 1)); | |
if (Dns4CacheEntry->HostName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen (Dns4TokenEntry->QueryHostName) + 1)); | |
Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS)); | |
if (Dns4CacheEntry->IpAddress == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS)); | |
if ((CNameTtl != 0) && (AnswerSection->Ttl != 0)) { | |
Dns4CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl); | |
} else { | |
Dns4CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl); | |
} | |
UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry); | |
// | |
// Free allocated CacheEntry pool. | |
// | |
FreePool (Dns4CacheEntry->HostName); | |
Dns4CacheEntry->HostName = NULL; | |
FreePool (Dns4CacheEntry->IpAddress); | |
Dns4CacheEntry->IpAddress = NULL; | |
FreePool (Dns4CacheEntry); | |
Dns4CacheEntry = NULL; | |
IpCount++; | |
Status = EFI_SUCCESS; | |
break; | |
case DNS_TYPE_AAAA: | |
// | |
// This is address entry, get Data. | |
// | |
ASSERT (Dns6TokenEntry != NULL); | |
if (AnswerSection->DataLength != 16) { | |
Status = EFI_ABORTED; | |
goto ON_EXIT; | |
} | |
HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList; | |
AnswerData = (UINT8 *)AnswerSection + sizeof (*AnswerSection); | |
CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS)); | |
// | |
// Allocate new CacheEntry pool to update DNS cache dynamically. | |
// | |
Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY)); | |
if (Dns6CacheEntry == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen (Dns6TokenEntry->QueryHostName) + 1)); | |
if (Dns6CacheEntry->HostName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen (Dns6TokenEntry->QueryHostName) + 1)); | |
Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS)); | |
if (Dns6CacheEntry->IpAddress == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ON_EXIT; | |
} | |
CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS)); | |
if ((CNameTtl != 0) && (AnswerSection->Ttl != 0)) { | |
Dns6CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl); | |
} else { | |
Dns6CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl); | |
} | |
UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry); | |
// | |
// Free allocated CacheEntry pool. | |
// | |
FreePool (Dns6CacheEntry->HostName); | |
Dns6CacheEntry->HostName = NULL; | |
FreePool (Dns6CacheEntry->IpAddress); | |
Dns6CacheEntry->IpAddress = NULL; | |
FreePool (Dns6CacheEntry); | |
Dns6CacheEntry = NULL; | |
IpCount++; | |
Status = EFI_SUCCESS; | |
break; | |
case DNS_TYPE_CNAME: | |
// | |
// According RFC 1034 - 3.6.2, if the query name is an alias, the name server will include the CNAME | |
// record in the response and restart the query at the domain name specified in the data field of the | |
// CNAME record. So, just record the TTL value of the CNAME, then skip to parse the next record. | |
// | |
CNameTtl = AnswerSection->Ttl; | |
break; | |
default: | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
} | |
// | |
// Find next one | |
// | |
AnswerName = (CHAR8 *)AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength; | |
AnswerSectionNum++; | |
} | |
if (Instance->Service->IpVersion == IP_VERSION_4) { | |
ASSERT (Dns4TokenEntry != NULL); | |
if (Dns4TokenEntry->GeneralLookUp) { | |
Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount; | |
} else { | |
if (QuerySection->Type == DNS_TYPE_A) { | |
Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount; | |
} else { | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
} | |
} else { | |
ASSERT (Dns6TokenEntry != NULL); | |
if (Dns6TokenEntry->GeneralLookUp) { | |
Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount; | |
} else { | |
if (QuerySection->Type == DNS_TYPE_AAAA) { | |
Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount; | |
} else { | |
Status = EFI_UNSUPPORTED; | |
goto ON_EXIT; | |
} | |
} | |
} | |
ON_COMPLETE: | |
// | |
// Parsing is complete, free the sending packet and signal Event here. | |
// | |
if ((Item != NULL) && (Item->Value != NULL)) { | |
NetbufFree ((NET_BUF *)(Item->Value)); | |
} | |
if (Instance->Service->IpVersion == IP_VERSION_4) { | |
ASSERT (Dns4TokenEntry != NULL); | |
Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry); | |
Dns4TokenEntry->Token->Status = Status; | |
if (Dns4TokenEntry->Token->Event != NULL) { | |
gBS->SignalEvent (Dns4TokenEntry->Token->Event); | |
DispatchDpc (); | |
} | |
} else { | |
ASSERT (Dns6TokenEntry != NULL); | |
Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry); | |
Dns6TokenEntry->Token->Status = Status; | |
if (Dns6TokenEntry->Token->Event != NULL) { | |
gBS->SignalEvent (Dns6TokenEntry->Token->Event); | |
DispatchDpc (); | |
} | |
} | |
ON_EXIT: | |
// | |
// Free the allocated buffer if error happen. | |
// | |
if (EFI_ERROR (Status)) { | |
if (Dns4TokenEntry != NULL) { | |
if (Dns4TokenEntry->GeneralLookUp) { | |
if (Dns4TokenEntry->Token->RspData.GLookupData != NULL) { | |
if (Dns4TokenEntry->Token->RspData.GLookupData->RRList != NULL) { | |
while (RRCount != 0) { | |
RRCount--; | |
if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) { | |
FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName); | |
} | |
if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) { | |
FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData); | |
} | |
} | |
FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList); | |
} | |
FreePool (Dns4TokenEntry->Token->RspData.GLookupData); | |
} | |
} else { | |
if ((QuerySection->Type == DNS_TYPE_A) && (Dns4TokenEntry->Token->RspData.H2AData != NULL)) { | |
if (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL) { | |
FreePool (Dns4TokenEntry->Token->RspData.H2AData->IpList); | |
} | |
FreePool (Dns4TokenEntry->Token->RspData.H2AData); | |
Dns4TokenEntry->Token->RspData.H2AData = NULL; | |
} | |
} | |
} | |
if (Dns6TokenEntry != NULL) { | |
if (Dns6TokenEntry->GeneralLookUp) { | |
if (Dns6TokenEntry->Token->RspData.GLookupData != NULL) { | |
if (Dns6TokenEntry->Token->RspData.GLookupData->RRList != NULL) { | |
while (RRCount != 0) { | |
RRCount--; | |
if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) { | |
FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName); | |
} | |
if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) { | |
FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData); | |
} | |
} | |
FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList); | |
} | |
FreePool (Dns6TokenEntry->Token->RspData.GLookupData); | |
} | |
} else { | |
if ((QuerySection->Type == DNS_TYPE_AAAA) && (Dns6TokenEntry->Token->RspData.H2AData != NULL)) { | |
if (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL) { | |
FreePool (Dns6TokenEntry->Token->RspData.H2AData->IpList); | |
} | |
FreePool (Dns6TokenEntry->Token->RspData.H2AData); | |
Dns6TokenEntry->Token->RspData.H2AData = NULL; | |
} | |
} | |
} | |
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); | |
} | |
} | |
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; | |
UINT32 Len; | |
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); | |
Len = Packet->TotalSize; | |
RcvString = NetbufGetByte (Packet, 0, NULL); | |
ASSERT (RcvString != NULL); | |
// | |
// Parse Dns Response | |
// | |
ParseDnsResponse (Instance, RcvString, Len, &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 according query section. | |
@param Instance The DNS instance | |
@param QueryName Queried Name | |
@param Type Queried Type | |
@param Class Queried Class | |
@param Packet The packet for query | |
@retval EFI_SUCCESS The packet is constructed. | |
@retval Others Failed to construct the Packet. | |
**/ | |
EFI_STATUS | |
ConstructDNSQuery ( | |
IN DNS_INSTANCE *Instance, | |
IN CHAR8 *QueryName, | |
IN UINT16 Type, | |
IN UINT16 Class, | |
OUT NET_BUF **Packet | |
) | |
{ | |
NET_FRAGMENT Frag; | |
DNS_HEADER *DnsHeader; | |
DNS_QUERY_SECTION *DnsQuery; | |
// | |
// Messages carried by UDP are restricted to 512 bytes (not counting the IP | |
// or UDP headers). | |
// | |
Frag.Bulk = AllocatePool (DNS_MAX_MESSAGE_SIZE * sizeof (UINT8)); | |
if (Frag.Bulk == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Fill header | |
// | |
DnsHeader = (DNS_HEADER *)Frag.Bulk; | |
DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed ()); | |
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 | |
// | |
CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName)); | |
Frag.Len = (UINT32)(Frag.Len + AsciiStrLen (QueryName)); | |
*(Frag.Bulk + Frag.Len) = 0; | |
Frag.Len++; | |
// | |
// Rest query section | |
// | |
DnsQuery = (DNS_QUERY_SECTION *)(Frag.Bulk + Frag.Len); | |
DnsQuery->Type = HTONS (Type); | |
DnsQuery->Class = HTONS (Class); | |
Frag.Len += sizeof (*DnsQuery); | |
// | |
// 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 maximum retry count, | |
// otherwise exit the transfer. | |
// | |
if (++Dns4TokenEntry->RetryCounting <= Dns4TokenEntry->Token->RetryCount) { | |
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 maximum retry count, | |
// otherwise exit the transfer. | |
// | |
if (++Dns6TokenEntry->RetryCounting <= Dns6TokenEntry->Token->RetryCount) { | |
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); | |
FreePool (Item4->DnsCache.HostName); | |
FreePool (Item4->DnsCache.IpAddress); | |
FreePool (Item4); | |
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); | |
FreePool (Item6->DnsCache.HostName); | |
FreePool (Item6->DnsCache.IpAddress); | |
FreePool (Item6); | |
Entry = mDriverData->Dns6CacheList.ForwardLink; | |
} else { | |
Entry = Entry->ForwardLink; | |
} | |
} | |
} |