audk/NetworkPkg/IScsiDxe/IScsiDns.c

436 lines
12 KiB
C

/** @file
Perform DNS resolution based on UEFI DNS protocols.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "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;
}