Replace unsafe string functions with new added safe string functions. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Qiu Shumin <shumin.qiu@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17881 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			473 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			473 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  iSCSI DHCP related configuration routines.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2015, 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.
 | 
						|
 | 
						|
  @param[in]        RootPath         The RootPath.
 | 
						|
  @param[in]        Length           Length of the RootPath option payload.
 | 
						|
  @param[in, out]   ConfigNvData     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 mal-formatted.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiDhcpExtractRootPath (
 | 
						|
  IN      CHAR8                        *RootPath,
 | 
						|
  IN      UINT8                        Length,
 | 
						|
  IN OUT  ISCSI_SESSION_CONFIG_NVDATA  *ConfigNvData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINT8                 IScsiRootPathIdLen;
 | 
						|
  CHAR8                 *TmpStr;
 | 
						|
  ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];
 | 
						|
  ISCSI_ROOT_PATH_FIELD *Field;
 | 
						|
  UINT32                FieldIndex;
 | 
						|
  UINT8                 Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
 | 
						|
  //
 | 
						|
  IScsiRootPathIdLen = (UINT8) 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 += IScsiRootPathIdLen;
 | 
						|
  Length  = (UINT8) (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      = RP_FIELD_IDX_SERVERNAME;
 | 
						|
  ZeroMem (&Fields[0], sizeof (Fields));
 | 
						|
 | 
						|
  //
 | 
						|
  // Extract the fields in the Root Path option string.
 | 
						|
  //
 | 
						|
  for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (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];
 | 
						|
  Status  = IScsiAsciiStrToIp (Field->Str, &ConfigNvData->TargetIp);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The callback function registerd to the DHCP4 instance which is used to select
 | 
						|
  the qualified DHCP OFFER.
 | 
						|
  
 | 
						|
  @param[in]  This         The DHCP4 protocol.
 | 
						|
  @param[in]  Context      The context set when configuring the DHCP4 protocol.
 | 
						|
  @param[in]  CurrentState The current state of the DHCP4 protocol.
 | 
						|
  @param[in]  Dhcp4Event   The event occurs in the current state.
 | 
						|
  @param[in]  Packet       The DHCP packet that is to be sent or already received. 
 | 
						|
  @param[out] NewPacket    The packet used to replace the above Packet.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS      Either the DHCP OFFER is qualified or we're not intereseted
 | 
						|
                           in the Dhcp4Event.
 | 
						|
  @retval EFI_NOT_READY    The DHCP OFFER packet doesn't match our requirements.
 | 
						|
  @retval Others           Other errors as indicated.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IScsiDhcpSelectOffer (
 | 
						|
  IN  EFI_DHCP4_PROTOCOL  * This,
 | 
						|
  IN  VOID                *Context,
 | 
						|
  IN  EFI_DHCP4_STATE     CurrentState,
 | 
						|
  IN  EFI_DHCP4_EVENT     Dhcp4Event,
 | 
						|
  IN  EFI_DHCP4_PACKET    * Packet, OPTIONAL
 | 
						|
  OUT EFI_DHCP4_PACKET    **NewPacket OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT32                  OptionCount;
 | 
						|
  EFI_DHCP4_PACKET_OPTION **OptionList;
 | 
						|
  UINT32                  Index;
 | 
						|
 | 
						|
  if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  OptionCount = 0;
 | 
						|
 | 
						|
  Status      = This->Parse (This, Packet, &OptionCount, NULL);
 | 
						|
  if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
 | 
						|
  if (OptionList == NULL) {
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = This->Parse (This, Packet, &OptionCount, OptionList);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (OptionList);
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < OptionCount; Index++) {
 | 
						|
    if (OptionList[Index]->OpCode != DHCP4_TAG_ROOT_PATH) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = IScsiDhcpExtractRootPath (
 | 
						|
              (CHAR8 *) &OptionList[Index]->Data[0],
 | 
						|
              OptionList[Index]->Length,
 | 
						|
              (ISCSI_SESSION_CONFIG_NVDATA *) Context
 | 
						|
              );
 | 
						|
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index == OptionCount) {
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (OptionList);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parse the DHCP ACK to get the address configuration and DNS information.
 | 
						|
 | 
						|
  @param[in]       Dhcp4        The DHCP4 protocol.
 | 
						|
  @param[in, out]  ConfigData   The session 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 mal-formatted.
 | 
						|
  @retval EFI_DEVICE_ERROR      Other errors as indicated.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiParseDhcpAck (
 | 
						|
  IN      EFI_DHCP4_PROTOCOL         *Dhcp4,
 | 
						|
  IN OUT  ISCSI_SESSION_CONFIG_DATA  *ConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_DHCP4_MODE_DATA     Dhcp4ModeData;
 | 
						|
  UINT32                  OptionCount;
 | 
						|
  EFI_DHCP4_PACKET_OPTION **OptionList;
 | 
						|
  UINT32                  Index;
 | 
						|
 | 
						|
  Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4ModeData.State != Dhcp4Bound) {
 | 
						|
    return EFI_NO_MAPPING;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (&ConfigData->NvData.LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
  CopyMem (&ConfigData->NvData.SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
  CopyMem (&ConfigData->NvData.Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  OptionCount = 0;
 | 
						|
  OptionList  = NULL;
 | 
						|
 | 
						|
  Status      = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
 | 
						|
  if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
 | 
						|
  if (OptionList == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (OptionList);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < OptionCount; Index++) {
 | 
						|
    //
 | 
						|
    // Get DNS server addresses and DHCP server address from this offer.
 | 
						|
    //
 | 
						|
    if (OptionList[Index]->OpCode == DHCP4_TAG_DNS) {
 | 
						|
 | 
						|
      if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Primary DNS server address.
 | 
						|
      //
 | 
						|
      CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
      if (OptionList[Index]->Length > 4) {
 | 
						|
        //
 | 
						|
        // Secondary DNS server address
 | 
						|
        //
 | 
						|
        CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));
 | 
						|
      }
 | 
						|
    } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {
 | 
						|
      if (OptionList[Index]->Length != 4) {
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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 session configuration data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | 
						|
  @retval EFI_NO_MEDIA          There was a media error.
 | 
						|
  @retval Others                Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiDoDhcp (
 | 
						|
  IN     EFI_HANDLE                 Image,
 | 
						|
  IN     EFI_HANDLE                 Controller,
 | 
						|
  IN OUT ISCSI_SESSION_CONFIG_DATA  *ConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE              Dhcp4Handle;
 | 
						|
  EFI_DHCP4_PROTOCOL      *Dhcp4;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_DHCP4_PACKET_OPTION *ParaList;
 | 
						|
  EFI_DHCP4_CONFIG_DATA   Dhcp4ConfigData;
 | 
						|
  BOOLEAN                 MediaPresent;
 | 
						|
  UINT8                   *Data;
 | 
						|
 | 
						|
  Dhcp4Handle = NULL;
 | 
						|
  Dhcp4       = NULL;
 | 
						|
  ParaList    = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check media status before do DHCP
 | 
						|
  //
 | 
						|
  MediaPresent = TRUE;
 | 
						|
  NetLibDetectMedia (Controller, &MediaPresent);
 | 
						|
  if (!MediaPresent) {
 | 
						|
    return EFI_NO_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a DHCP4 child instance and get the protocol.
 | 
						|
  //
 | 
						|
  Status = NetLibCreateServiceChild (
 | 
						|
            Controller,
 | 
						|
            Image,
 | 
						|
            &gEfiDhcp4ServiceBindingProtocolGuid,
 | 
						|
            &Dhcp4Handle
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Dhcp4Handle,
 | 
						|
                  &gEfiDhcp4ProtocolGuid,
 | 
						|
                  (VOID **)&Dhcp4,
 | 
						|
                  Image,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);
 | 
						|
  if (ParaList == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Ask the server to reply with Netmask, Router, DNS and RootPath options.
 | 
						|
  //
 | 
						|
  ParaList->OpCode  = DHCP4_TAG_PARA_LIST;
 | 
						|
  ParaList->Length  = (UINT8) (ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);
 | 
						|
  Data = &ParaList->Data[0];
 | 
						|
  Data[0] = DHCP4_TAG_NETMASK;
 | 
						|
  Data[1] = DHCP4_TAG_ROUTER;
 | 
						|
  Data[2] = DHCP4_TAG_DNS;
 | 
						|
  Data[3] = DHCP4_TAG_ROOT_PATH;
 | 
						|
 | 
						|
  ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));
 | 
						|
  Dhcp4ConfigData.OptionCount = 1;
 | 
						|
  Dhcp4ConfigData.OptionList  = &ParaList;
 | 
						|
 | 
						|
  if (ConfigData->NvData.TargetInfoFromDhcp) {
 | 
						|
    //
 | 
						|
    // Use callback to select an offer which contains target information.
 | 
						|
    //
 | 
						|
    Dhcp4ConfigData.Dhcp4Callback   = IScsiDhcpSelectOffer;
 | 
						|
    Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Dhcp4->Start (Dhcp4, NULL);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Parse the ACK to get required information.
 | 
						|
  //
 | 
						|
  Status = IScsiParseDhcpAck (Dhcp4, ConfigData);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  if (ParaList != NULL) {
 | 
						|
    FreePool (ParaList);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4 != NULL) {
 | 
						|
    Dhcp4->Stop (Dhcp4);
 | 
						|
    Dhcp4->Configure (Dhcp4, NULL);
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Dhcp4Handle,
 | 
						|
          &gEfiDhcp4ProtocolGuid,
 | 
						|
          Image,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  }
 | 
						|
 | 
						|
  NetLibDestroyServiceChild (
 | 
						|
    Controller,
 | 
						|
    Image,
 | 
						|
    &gEfiDhcp4ServiceBindingProtocolGuid,
 | 
						|
    Dhcp4Handle
 | 
						|
    );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |