if the server name expressed as a site local address begain with FEC0 when retrieving from dhcpv6 option 59 boot file url, it incorrectly process it as a dns name. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Cc: Wu Jiaxin <jiaxin.wu@intel.com> Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Wu Jiaxin <jiaxin.wu@intel.com>
		
			
				
	
	
		
			551 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			551 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   iSCSI DHCP6 related configuration routines.
 | |
| 
 | |
| Copyright (c) 2009 - 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"
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Extract the Root Path option and get the required target information from
 | |
|   Boot File Uniform Resource Locator (URL) Option.
 | |
| 
 | |
|   @param[in]       RootPath      The RootPath string.
 | |
|   @param[in]       Length        Length of the RootPath option payload.
 | |
|   @param[in, out]  ConfigData    The iSCSI session configuration data read from
 | |
|                                  nonvolatile device.
 | |
| 
 | |
|   @retval EFI_SUCCESS            All required information is extracted from the
 | |
|                                  RootPath option.
 | |
|   @retval EFI_NOT_FOUND          The RootPath is not an iSCSI RootPath.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | |
|   @retval EFI_INVALID_PARAMETER  The RootPath is malformatted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiDhcp6ExtractRootPath (
 | |
|   IN     CHAR8                        *RootPath,
 | |
|   IN     UINT16                       Length,
 | |
|   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT16                      IScsiRootPathIdLen;
 | |
|   CHAR8                       *TmpStr;
 | |
|   ISCSI_ROOT_PATH_FIELD       Fields[RP_FIELD_IDX_MAX];
 | |
|   ISCSI_ROOT_PATH_FIELD       *Field;
 | |
|   UINT32                      FieldIndex;
 | |
|   UINT8                       Index;
 | |
|   ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
 | |
|   EFI_IP_ADDRESS              Ip;
 | |
|   UINT8                       IpMode;  
 | |
| 
 | |
|   ConfigNvData = &ConfigData->SessionConfigData;
 | |
|   ConfigNvData->DnsMode = FALSE;
 | |
|   //
 | |
|   // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
 | |
|   //
 | |
|   IScsiRootPathIdLen = (UINT16) AsciiStrLen (ISCSI_ROOT_PATH_ID);
 | |
| 
 | |
|   if ((Length <= IScsiRootPathIdLen) ||
 | |
|       (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // Skip the iSCSI RootPath ID "iscsi:".
 | |
|   //
 | |
|   RootPath = RootPath + IScsiRootPathIdLen;
 | |
|   Length   = (UINT16) (Length - IScsiRootPathIdLen);
 | |
| 
 | |
|   TmpStr   = (CHAR8 *) AllocatePool (Length + 1);
 | |
|   if (TmpStr == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CopyMem (TmpStr, RootPath, Length);
 | |
|   TmpStr[Length]  = '\0';
 | |
| 
 | |
|   Index           = 0;
 | |
|   FieldIndex      = 0;
 | |
|   ZeroMem (&Fields[0], sizeof (Fields));
 | |
| 
 | |
|   //
 | |
|   // Extract SERVERNAME field in the Root Path option.
 | |
|   //
 | |
|   if (TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_START_DELIMITER) {
 | |
|     //
 | |
|     // The servername is expressed as domain name.
 | |
|     //
 | |
|     ConfigNvData->DnsMode = TRUE;
 | |
|   } else {
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   Fields[RP_FIELD_IDX_SERVERNAME].Str = &TmpStr[Index];
 | |
| 
 | |
|   if (!ConfigNvData->DnsMode) {
 | |
|     while ((TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_END_DELIMITER)&& (Index < Length)) {
 | |
|       Index++;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip ']' and ':'.
 | |
|     //
 | |
|     TmpStr[Index] = '\0';
 | |
|     Index += 2;
 | |
|   } else {
 | |
|     while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
 | |
|       Index++;
 | |
|     }
 | |
|     //
 | |
|     // Skip ':'.
 | |
|     //
 | |
|     TmpStr[Index] = '\0';
 | |
|     Index += 1;
 | |
|   }
 | |
| 
 | |
|   Fields[RP_FIELD_IDX_SERVERNAME].Len = (UINT8) AsciiStrLen (Fields[RP_FIELD_IDX_SERVERNAME].Str);
 | |
| 
 | |
|   //
 | |
|   // Extract others fields in the Root Path option string.
 | |
|   //
 | |
|   for (FieldIndex = 1; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
 | |
| 
 | |
|     if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
 | |
|       Fields[FieldIndex].Str = &TmpStr[Index];
 | |
|     }
 | |
| 
 | |
|     while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
 | |
|       Index++;
 | |
|     }
 | |
| 
 | |
|     if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
 | |
|       if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
 | |
|         TmpStr[Index] = '\0';
 | |
|         Index++;
 | |
|       }
 | |
| 
 | |
|       if (Fields[FieldIndex].Str != NULL) {
 | |
|         Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (FieldIndex != RP_FIELD_IDX_MAX) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
 | |
|       (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
 | |
|       (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
 | |
|       ) {
 | |
| 
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
|   //
 | |
|   // Get the IP address of the target.
 | |
|   //
 | |
|   Field   = &Fields[RP_FIELD_IDX_SERVERNAME];  
 | |
|   if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
 | |
|     IpMode = ConfigNvData->IpMode;
 | |
|   } else {
 | |
|     IpMode = ConfigData->AutoConfigureMode;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Server name is expressed as domain name, just save it.
 | |
|   //
 | |
|   if (ConfigNvData->DnsMode) {
 | |
|     if (Field->Len > sizeof (ConfigNvData->TargetUrl)) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);
 | |
|     ConfigNvData->TargetUrl[Field->Len + 1] = '\0';
 | |
|   } else {
 | |
|     ZeroMem(&ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));
 | |
|     Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
 | |
|     CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the protocol type.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_PROTOCOL];
 | |
|   if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
|   //
 | |
|   // Get the port of the iSCSI target.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_PORT];
 | |
|   if (Field->Str != NULL) {
 | |
|     ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);
 | |
|   } else {
 | |
|     ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
 | |
|   }
 | |
|   //
 | |
|   // Get the LUN.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_LUN];
 | |
|   if (Field->Str != NULL) {
 | |
|     Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   } else {
 | |
|     ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
 | |
|   }
 | |
|   //
 | |
|   // Get the target iSCSI Name.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_TARGETNAME];
 | |
| 
 | |
|   if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
|   //
 | |
|   // Validate the iSCSI name.
 | |
|   //
 | |
|   Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   FreePool (TmpStr);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol 
 | |
|   instance to intercept events that occurs in the DHCPv6 Information Request
 | |
|   exchange process.
 | |
| 
 | |
|   @param[in]  This              Pointer to the EFI_DHCP6_PROTOCOL instance that 
 | |
|                                 is used to configure this  callback function.
 | |
|   @param[in]  Context           Pointer to the context that is initialized in
 | |
|                                 the EFI_DHCP6_PROTOCOL.InfoRequest().
 | |
|   @param[in]  Packet            Pointer to Reply packet that has been received.
 | |
|                                 The EFI DHCPv6 Protocol instance is responsible
 | |
|                                 for freeing the buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Tell the EFI DHCPv6 Protocol instance to finish
 | |
|                                 Information Request exchange process.
 | |
|   @retval EFI_NOT_READY         Tell the EFI DHCPv6 Protocol instance to continue
 | |
|                                 Information Request exchange process.
 | |
|   @retval EFI_ABORTED           Tell the EFI DHCPv6 Protocol instance to abort
 | |
|                                 the Information Request exchange process.
 | |
|   @retval EFI_UNSUPPORTED       Tell the EFI DHCPv6 Protocol instance to finish
 | |
|                                 the Information Request exchange process because some
 | |
|                                 request information are not received.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IScsiDhcp6ParseReply (
 | |
|   IN EFI_DHCP6_PROTOCOL          *This,
 | |
|   IN VOID                        *Context,
 | |
|   IN EFI_DHCP6_PACKET            *Packet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT32                      Index;
 | |
|   UINT32                      OptionCount;
 | |
|   EFI_DHCP6_PACKET_OPTION     *BootFileOpt;
 | |
|   EFI_DHCP6_PACKET_OPTION     **OptionList;
 | |
|   ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;
 | |
|   UINT16                      ParaLen;
 | |
|  
 | |
|   OptionCount = 0;
 | |
|   BootFileOpt = NULL;
 | |
|   
 | |
|   Status      = This->Parse (This, Packet, &OptionCount, NULL);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
 | |
|   if (OptionList == NULL) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   Status = This->Parse (This, Packet, &OptionCount, OptionList);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_NOT_READY;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context;
 | |
| 
 | |
|   for (Index = 0; Index < OptionCount; Index++) {
 | |
|     OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
 | |
|     OptionList[Index]->OpLen  = NTOHS (OptionList[Index]->OpLen);
 | |
| 
 | |
|     //
 | |
|     // Get DNS server addresses from this reply packet.
 | |
|     //
 | |
|     if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {
 | |
| 
 | |
|       if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto Exit;
 | |
|       }
 | |
|       //
 | |
|       // Primary DNS server address.
 | |
|       //
 | |
|       CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|       if (OptionList[Index]->OpLen > 16) {
 | |
|         //
 | |
|         // Secondary DNS server address
 | |
|         //
 | |
|         CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));
 | |
|       }
 | |
| 
 | |
|     } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {
 | |
|       //
 | |
|       // The server sends this option to inform the client about an URL to a boot file.
 | |
|       //
 | |
|       BootFileOpt = OptionList[Index];
 | |
|     } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_PARAM) {
 | |
|       //
 | |
|       // The server sends this option to inform the client about DHCP6 server address.
 | |
|       //
 | |
|       if (OptionList[Index]->OpLen < 18) {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto Exit;
 | |
|       }
 | |
|       //
 | |
|       // Check param-len 1, should be 16 bytes.
 | |
|       //
 | |
|       CopyMem (&ParaLen, &OptionList[Index]->Data[0], sizeof (UINT16));
 | |
|       if (NTOHS (ParaLen) != 16) {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto Exit;
 | |
|       }
 | |
| 
 | |
|       CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[2], sizeof (EFI_IPv6_ADDRESS));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (BootFileOpt == NULL) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto Exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option
 | |
|   //
 | |
|   Status = IScsiDhcp6ExtractRootPath (
 | |
|              (CHAR8 *) BootFileOpt->Data,
 | |
|              BootFileOpt->OpLen,
 | |
|              ConfigData
 | |
|              );
 | |
| 
 | |
| Exit:
 | |
| 
 | |
|   FreePool (OptionList);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Parse the DHCP ACK to get the address configuration and DNS information.
 | |
| 
 | |
|   @param[in]       Image         The handle of the driver image.
 | |
|   @param[in]       Controller    The handle of the controller;
 | |
|   @param[in, out]  ConfigData    The attempt configuration data.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The DNS information is got from the DHCP ACK.
 | |
|   @retval EFI_NO_MAPPING         DHCP failed to acquire address and other
 | |
|                                  information.
 | |
|   @retval EFI_INVALID_PARAMETER  The DHCP ACK's DNS option is malformatted.
 | |
|   @retval EFI_DEVICE_ERROR       Some unexpected error occurred.
 | |
|   @retval EFI_OUT_OF_RESOURCES   There is no sufficient resource to finish the
 | |
|                                  operation.
 | |
|   @retval EFI_NO_MEDIA           There was a media error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiDoDhcp6 (
 | |
|   IN     EFI_HANDLE                  Image,
 | |
|   IN     EFI_HANDLE                  Controller,
 | |
|   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_HANDLE                Dhcp6Handle;
 | |
|   EFI_DHCP6_PROTOCOL        *Dhcp6;
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_STATUS                TimerStatus;
 | |
|   EFI_DHCP6_PACKET_OPTION   *Oro;
 | |
|   EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
 | |
|   EFI_EVENT                 Timer;
 | |
|   BOOLEAN                   MediaPresent;
 | |
| 
 | |
|   //
 | |
|   // Check media status before doing DHCP.
 | |
|   //
 | |
|   MediaPresent = TRUE;
 | |
|   NetLibDetectMedia (Controller, &MediaPresent);
 | |
|   if (!MediaPresent) {
 | |
|     return EFI_NO_MEDIA;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // iSCSI will only request target info from DHCPv6 server.
 | |
|   //
 | |
|   if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   Dhcp6Handle = NULL;
 | |
|   Dhcp6       = NULL;
 | |
|   Oro         = NULL;
 | |
|   Timer       = NULL;
 | |
| 
 | |
|   //
 | |
|   // Create a DHCP6 child instance and get the protocol.
 | |
|   //
 | |
|   Status = NetLibCreateServiceChild (
 | |
|              Controller,
 | |
|              Image,
 | |
|              &gEfiDhcp6ServiceBindingProtocolGuid,
 | |
|              &Dhcp6Handle
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Dhcp6Handle,
 | |
|                   &gEfiDhcp6ProtocolGuid,
 | |
|                   (VOID **) &Dhcp6,
 | |
|                   Image,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 5);
 | |
|   if (Oro == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Ask the server to reply with DNS and Boot File URL options by info request.
 | |
|   // All members in EFI_DHCP6_PACKET_OPTION are in network order.
 | |
|   //
 | |
|   Oro->OpCode  = HTONS (DHCP6_OPT_ORO);
 | |
|   Oro->OpLen   = HTONS (2 * 3);
 | |
|   Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;
 | |
|   Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;
 | |
|   Oro->Data[5] = DHCP6_OPT_BOOT_FILE_PARAM;
 | |
| 
 | |
|   InfoReqReXmit.Irt = 4;
 | |
|   InfoReqReXmit.Mrc = 1;
 | |
|   InfoReqReXmit.Mrt = 10;
 | |
|   InfoReqReXmit.Mrd = 30;
 | |
| 
 | |
|   Status = Dhcp6->InfoRequest (
 | |
|                     Dhcp6,
 | |
|                     TRUE,
 | |
|                     Oro,
 | |
|                     0,
 | |
|                     NULL,
 | |
|                     &InfoReqReXmit,
 | |
|                     NULL,
 | |
|                     IScsiDhcp6ParseReply,
 | |
|                     ConfigData
 | |
|                     );
 | |
|   if (Status == EFI_NO_MAPPING) {
 | |
|     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->SetTimer (
 | |
|                     Timer,
 | |
|                     TimerRelative,
 | |
|                     ISCSI_GET_MAPPING_TIMEOUT
 | |
|                     );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     do {
 | |
| 
 | |
|       TimerStatus = gBS->CheckEvent (Timer);
 | |
| 
 | |
|       if (!EFI_ERROR (TimerStatus)) {
 | |
|         Status = Dhcp6->InfoRequest (
 | |
|                           Dhcp6,
 | |
|                           TRUE,
 | |
|                           Oro,
 | |
|                           0,
 | |
|                           NULL,
 | |
|                           &InfoReqReXmit,
 | |
|                           NULL,
 | |
|                           IScsiDhcp6ParseReply,
 | |
|                           ConfigData
 | |
|                           );
 | |
|       }
 | |
| 
 | |
|     } while (TimerStatus == EFI_NOT_READY);
 | |
| 
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   if (Oro != NULL) {
 | |
|     FreePool (Oro);
 | |
|   }  
 | |
| 
 | |
|   if (Timer != NULL) {
 | |
|     gBS->CloseEvent (Timer);
 | |
|   }
 | |
| 
 | |
|   if (Dhcp6 != NULL) {
 | |
|     gBS->CloseProtocol (
 | |
|            Dhcp6Handle,
 | |
|            &gEfiDhcp6ProtocolGuid,
 | |
|            Image,
 | |
|            Controller
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   NetLibDestroyServiceChild (
 | |
|     Controller,
 | |
|     Image,
 | |
|     &gEfiDhcp6ServiceBindingProtocolGuid,
 | |
|     Dhcp6Handle
 | |
|     );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |