CloverBootloader/NetworkPkg/IScsiDxe/IScsiDns.c

436 lines
11 KiB
C

/** @file
Perform DNS resolution based on UEFI DNS protocols.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "IScsiImpl.h"
/**
Notify the callback function when an event is triggered.
@param[in] Event The triggered event.
@param[in] Context The opaque parameter to the function.
**/
VOID
EFIAPI
IScsiCommonNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
*((BOOLEAN *)Context) = TRUE;
}
/**
Retrieve the host address using the EFI_DNS4_PROTOCOL.
@param[in] Image The handle of the driver image.
@param[in] Controller The handle of the controller.
@param[in, out] NvData The Session config data structure.
@retval EFI_SUCCESS Operation succeeded.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
@retval EFI_DEVICE_ERROR An unexpected network error occurred.
@retval Others Other errors as indicated.
**/
EFI_STATUS
IScsiDns4 (
IN EFI_HANDLE Image,
IN EFI_HANDLE Controller,
IN OUT ISCSI_SESSION_CONFIG_NVDATA *NvData
)
{
EFI_STATUS Status;
EFI_DNS4_PROTOCOL *Dns4;
EFI_DNS4_CONFIG_DATA Dns4CfgData;
EFI_DNS4_COMPLETION_TOKEN Token;
BOOLEAN IsDone;
EFI_HANDLE Dns4Handle;
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
EFI_IPv4_ADDRESS *DnsServerList;
UINTN DnsServerListCount;
UINTN DataSize;
CHAR16 *HostName;
DnsServerList = NULL;
DnsServerListCount = 0;
Dns4Handle = NULL;
Dns4 = NULL;
ZeroMem (&Token, sizeof (EFI_DNS4_COMPLETION_TOKEN));
//
// Get DNS server list from EFI IPv4 Configuration II protocol.
//
Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **)&Ip4Config2);
if (!EFI_ERROR (Status)) {
//
// Get the required size.
//
DataSize = 0;
Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, NULL);
if (Status == EFI_BUFFER_TOO_SMALL) {
DnsServerList = AllocatePool (DataSize);
if (DnsServerList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, DnsServerList);
if (EFI_ERROR (Status)) {
FreePool (DnsServerList);
DnsServerList = NULL;
} else {
DnsServerListCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
}
}
}
//
// Create a DNS child instance and get the protocol.
//
Status = NetLibCreateServiceChild (
Controller,
Image,
&gEfiDns4ServiceBindingProtocolGuid,
&Dns4Handle
);
if (EFI_ERROR (Status)) {
goto Exit;
}
Status = gBS->OpenProtocol (
Dns4Handle,
&gEfiDns4ProtocolGuid,
(VOID **)&Dns4,
Image,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Configure DNS4 instance for the DNS server address and protocol.
//
ZeroMem (&Dns4CfgData, sizeof (Dns4CfgData));
Dns4CfgData.DnsServerListCount = DnsServerListCount;
Dns4CfgData.DnsServerList = DnsServerList;
Dns4CfgData.EnableDnsCache = TRUE;
IP4_COPY_ADDRESS (&Dns4CfgData.StationIp, &NvData->LocalIp);
IP4_COPY_ADDRESS (&Dns4CfgData.SubnetMask, &NvData->SubnetMask);
Dns4CfgData.Protocol = EFI_IP_PROTO_UDP;
Status = Dns4->Configure (
Dns4,
&Dns4CfgData
);
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Create event to set the is done flag when name resolution is finished.
//
ZeroMem (&Token, sizeof (Token));
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
IScsiCommonNotify,
&IsDone,
&Token.Event
);
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Start asynchronous name resolution.
//
Token.Status = EFI_NOT_READY;
IsDone = FALSE;
HostName = (CHAR16 *)AllocateZeroPool (ISCSI_NAME_MAX_SIZE);
if (HostName == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AsciiStrToUnicodeStrS (
NvData->TargetUrl,
HostName,
ISCSI_NAME_MAX_SIZE
);
Status = Dns4->HostNameToIp (Dns4, HostName, &Token);
if (EFI_ERROR (Status)) {
goto Exit;
}
while (!IsDone) {
Dns4->Poll (Dns4);
}
//
// Name resolution is done, check result.
//
Status = Token.Status;
if (!EFI_ERROR (Status)) {
if (Token.RspData.H2AData == NULL) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
//
// We just return the first IP address from DNS protocol.
//
IP4_COPY_ADDRESS (&NvData->TargetIp.v4, Token.RspData.H2AData->IpList);
Status = EFI_SUCCESS;
}
Exit:
if (Token.Event != NULL) {
gBS->CloseEvent (Token.Event);
}
if (Token.RspData.H2AData != NULL) {
if (Token.RspData.H2AData->IpList != NULL) {
FreePool (Token.RspData.H2AData->IpList);
}
FreePool (Token.RspData.H2AData);
}
if (Dns4 != NULL) {
Dns4->Configure (Dns4, NULL);
gBS->CloseProtocol (
Dns4Handle,
&gEfiDns4ProtocolGuid,
Image,
Controller
);
}
if (Dns4Handle != NULL) {
NetLibDestroyServiceChild (
Controller,
Image,
&gEfiDns4ServiceBindingProtocolGuid,
Dns4Handle
);
}
return Status;
}
/**
Retrieve the host address using the EFI_DNS6_PROTOCOL.
@param[in] Image The handle of the driver image.
@param[in] Controller The handle of the controller.
@param[in, out] NvData The Session config data structure.
@retval EFI_SUCCESS Operation succeeded.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
@retval EFI_DEVICE_ERROR An unexpected network error occurred.
@retval Others Other errors as indicated.
**/
EFI_STATUS
IScsiDns6 (
IN EFI_HANDLE Image,
IN EFI_HANDLE Controller,
IN OUT ISCSI_SESSION_CONFIG_NVDATA *NvData
)
{
EFI_STATUS Status;
EFI_DNS6_PROTOCOL *Dns6;
EFI_DNS6_CONFIG_DATA Dns6ConfigData;
EFI_DNS6_COMPLETION_TOKEN Token;
EFI_HANDLE Dns6Handle;
EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
EFI_IPv6_ADDRESS *DnsServerList;
UINTN DnsServerListCount;
UINTN DataSize;
BOOLEAN IsDone;
CHAR16 *HostName;
DnsServerList = NULL;
DnsServerListCount = 0;
Dns6 = NULL;
Dns6Handle = NULL;
ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));
//
// Get DNS server list from EFI IPv6 Configuration protocol.
//
Status = gBS->HandleProtocol (Controller, &gEfiIp6ConfigProtocolGuid, (VOID **)&Ip6Config);
if (!EFI_ERROR (Status)) {
//
// Get the required size.
//
DataSize = 0;
Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);
if (Status == EFI_BUFFER_TOO_SMALL) {
DnsServerList = AllocatePool (DataSize);
if (DnsServerList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);
if (EFI_ERROR (Status)) {
FreePool (DnsServerList);
DnsServerList = NULL;
} else {
DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
}
}
}
//
// Create a DNSv6 child instance and get the protocol.
//
Status = NetLibCreateServiceChild (
Controller,
Image,
&gEfiDns6ServiceBindingProtocolGuid,
&Dns6Handle
);
if (EFI_ERROR (Status)) {
goto Exit;
}
Status = gBS->OpenProtocol (
Dns6Handle,
&gEfiDns6ProtocolGuid,
(VOID **)&Dns6,
Image,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Configure DNS6 instance for the DNS server address and protocol.
//
ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));
Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;
Dns6ConfigData.DnsServerList = DnsServerList;
Dns6ConfigData.EnableDnsCache = TRUE;
Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;
Status = Dns6->Configure (
Dns6,
&Dns6ConfigData
);
if (EFI_ERROR (Status)) {
goto Exit;
}
Token.Status = EFI_NOT_READY;
IsDone = FALSE;
//
// Create event to set the IsDone flag when name resolution is finished.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
IScsiCommonNotify,
&IsDone,
&Token.Event
);
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Start asynchronous name resolution.
//
HostName = (CHAR16 *)AllocateZeroPool (ISCSI_NAME_MAX_SIZE);
if (HostName == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AsciiStrToUnicodeStrS (
NvData->TargetUrl,
HostName,
ISCSI_NAME_MAX_SIZE
);
Status = Dns6->HostNameToIp (Dns6, HostName, &Token);
if (EFI_ERROR (Status)) {
goto Exit;
}
while (!IsDone) {
Dns6->Poll (Dns6);
}
//
// Name resolution is done, check result.
//
Status = Token.Status;
if (!EFI_ERROR (Status)) {
if (Token.RspData.H2AData == NULL) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
//
// We just return the first IPv6 address from DNS protocol.
//
IP6_COPY_ADDRESS (&NvData->TargetIp.v6, Token.RspData.H2AData->IpList);
Status = EFI_SUCCESS;
}
Exit:
if (Token.Event != NULL) {
gBS->CloseEvent (Token.Event);
}
if (Token.RspData.H2AData != NULL) {
if (Token.RspData.H2AData->IpList != NULL) {
FreePool (Token.RspData.H2AData->IpList);
}
FreePool (Token.RspData.H2AData);
}
if (Dns6 != NULL) {
Dns6->Configure (Dns6, NULL);
gBS->CloseProtocol (
Dns6Handle,
&gEfiDns6ProtocolGuid,
Image,
Controller
);
}
if (Dns6Handle != NULL) {
NetLibDestroyServiceChild (
Controller,
Image,
&gEfiDns6ServiceBindingProtocolGuid,
Dns6Handle
);
}
return Status;
}