v2: *1. Add IScsiDnsIsConfigured function in IScsiSupported to check attempt using DNS protocol or not.2. Fix wrongs typos in IScsiDns.c and .uni file.3. define a macro for the length of target URL.4. update the Copyright to 2017. Add DNS support for target URL directly configuration in UI. Besides, When we enable the option (Get target info via DHCP) , the dhcp server will return target info include the rootpath, like the format "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname> According to the RFC 4173,the server name region is expressed as IPv4(192.168.10.20 )or IPv6 ([2000:bbbb::3]) or domain name, but currently we only support the IP address format. To enable this feature, we can support both. Another enhancement is that we can deal with the data received from the iSCSI login response with an target redirection status, in which contains the Target Address in the format domainname[:port][,portal-group-tag] required by RFC 3720. Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Cc: Wu Jiaxin <jiaxin.wu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Reviewed-by: Wu Jiaxin <jiaxin.wu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
		
			
				
	
	
		
			436 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			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;
 | |
| }
 | |
| 
 |