430 lines
11 KiB
C
430 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;
|
||
|
}
|
||
|
|