Signed-off-by: tye Reviewed-by: niruiyu Adopt SasEx and new IPv6 device path for DevicePathDxe driver. Signed-off-by: niruiyu Reviewed-by: erictian git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12574 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1343 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1343 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Miscellaneous routines for iSCSI driver.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2011, 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"
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8  IScsiHexString[] = "0123456789ABCDEFabcdef";
 | 
						|
 | 
						|
/**
 | 
						|
  Removes (trims) specified leading and trailing characters from a string.
 | 
						|
 | 
						|
  @param[in, out] Str   Pointer to the null-terminated string to be trimmed.
 | 
						|
                        On return, Str will hold the trimmed string. 
 | 
						|
 | 
						|
  @param[in]      CharC Character will be trimmed from str.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiStrTrim (
 | 
						|
  IN OUT CHAR16   *Str,
 | 
						|
  IN     CHAR16   CharC
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *Pointer1;
 | 
						|
  CHAR16  *Pointer2;
 | 
						|
  
 | 
						|
  if (*Str == 0) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Trim off the leading and trailing characters c
 | 
						|
  //
 | 
						|
  for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
 | 
						|
    ;
 | 
						|
  }
 | 
						|
  
 | 
						|
  Pointer2 = Str;
 | 
						|
  if (Pointer2 == Pointer1) {
 | 
						|
    while (*Pointer1 != 0) {
 | 
						|
      Pointer2++;
 | 
						|
      Pointer1++;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    while (*Pointer1 != 0) {    
 | 
						|
    *Pointer2 = *Pointer1;    
 | 
						|
    Pointer1++;
 | 
						|
    Pointer2++;
 | 
						|
    }
 | 
						|
    *Pointer2 = 0;
 | 
						|
  }
 | 
						|
  
 | 
						|
  
 | 
						|
  for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
 | 
						|
    ;
 | 
						|
  }
 | 
						|
  if  (Pointer1 !=  Str + StrLen(Str) - 1) { 
 | 
						|
    *(Pointer1 + 1) = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate the prefix length of the IPv4 subnet mask.
 | 
						|
 | 
						|
  @param[in]  SubnetMask The IPv4 subnet mask.
 | 
						|
 | 
						|
  @return     The prefix length of the subnet mask.
 | 
						|
  @retval 0   Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
UINT8
 | 
						|
IScsiGetSubnetMaskPrefixLength (
 | 
						|
  IN EFI_IPv4_ADDRESS  *SubnetMask
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   Len;
 | 
						|
  UINT32  ReverseMask;
 | 
						|
 | 
						|
  //
 | 
						|
  // The SubnetMask is in network byte order.
 | 
						|
  //
 | 
						|
  ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
 | 
						|
 | 
						|
  //
 | 
						|
  // Reverse it.
 | 
						|
  //
 | 
						|
  ReverseMask = ~ReverseMask;
 | 
						|
 | 
						|
  if ((ReverseMask & (ReverseMask + 1)) != 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Len = 0;
 | 
						|
 | 
						|
  while (ReverseMask != 0) {
 | 
						|
    ReverseMask = ReverseMask >> 1;
 | 
						|
    Len++;
 | 
						|
  }
 | 
						|
 | 
						|
  return (UINT8) (32 - Len);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the hexadecimal encoded LUN string into the 64-bit LUN.
 | 
						|
 | 
						|
  @param[in]   Str             The hexadecimal encoded LUN string.
 | 
						|
  @param[out]  Lun             Storage to return the 64-bit LUN.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The 64-bit LUN is stored in Lun.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The string is malformatted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiAsciiStrToLun (
 | 
						|
  IN  CHAR8  *Str,
 | 
						|
  OUT UINT8  *Lun
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index, IndexValue, IndexNum, SizeStr;
 | 
						|
  CHAR8   TemStr[2];
 | 
						|
  UINT8   TemValue;
 | 
						|
  UINT16  Value[4];
 | 
						|
  
 | 
						|
  ZeroMem (Lun, 8);
 | 
						|
  ZeroMem (TemStr, 2);
 | 
						|
  ZeroMem ((UINT8 *) Value, sizeof (Value));
 | 
						|
  SizeStr    = AsciiStrLen (Str);  
 | 
						|
  IndexValue = 0;
 | 
						|
  IndexNum   = 0;
 | 
						|
 | 
						|
  for (Index = 0; Index < SizeStr; Index ++) {
 | 
						|
    TemStr[0] = Str[Index];
 | 
						|
    TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);
 | 
						|
    if (TemValue == 0 && TemStr[0] != '0') {
 | 
						|
      if ((TemStr[0] != '-') || (IndexNum == 0)) {
 | 
						|
        //
 | 
						|
        // Invalid Lun Char.
 | 
						|
        //
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ((TemValue == 0) && (TemStr[0] == '-')) {
 | 
						|
      //
 | 
						|
      // Next Lun value.
 | 
						|
      //
 | 
						|
      if (++IndexValue >= 4) {
 | 
						|
        //
 | 
						|
        // Max 4 Lun value.
 | 
						|
        //
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Restart str index for the next lun value.
 | 
						|
      //
 | 
						|
      IndexNum = 0;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (++IndexNum > 4) {
 | 
						|
      //     
 | 
						|
      // Each Lun Str can't exceed size 4, because it will be as UINT16 value.
 | 
						|
      //
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Combine UINT16 value.
 | 
						|
    //
 | 
						|
    Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
 | 
						|
  }
 | 
						|
 
 | 
						|
  for (Index = 0; Index <= IndexValue; Index ++) {
 | 
						|
    *((UINT16 *) &Lun[Index * 2]) =  HTONS (Value[Index]);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the 64-bit LUN into the hexadecimal encoded LUN string.
 | 
						|
 | 
						|
  @param[in]   Lun The 64-bit LUN.
 | 
						|
  @param[out]  Str The storage to return the hexadecimal encoded LUN string.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiLunToUnicodeStr (
 | 
						|
  IN UINT8    *Lun,
 | 
						|
  OUT CHAR16  *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index;
 | 
						|
  CHAR16  *TempStr;
 | 
						|
 | 
						|
  TempStr = Str;
 | 
						|
 | 
						|
  for (Index = 0; Index < 4; Index++) {
 | 
						|
 | 
						|
    if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
 | 
						|
      StrCpy (TempStr, L"0-");
 | 
						|
    } else {
 | 
						|
      TempStr[0]  = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];
 | 
						|
      TempStr[1]  = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];
 | 
						|
      TempStr[2]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];
 | 
						|
      TempStr[3]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];
 | 
						|
      TempStr[4]  = L'-';
 | 
						|
      TempStr[5]  = 0;
 | 
						|
 | 
						|
      IScsiStrTrim (TempStr, L'0');
 | 
						|
    }
 | 
						|
 | 
						|
    TempStr += StrLen (TempStr);
 | 
						|
  }
 | 
						|
 | 
						|
  Str[StrLen (Str) - 1] = 0;
 | 
						|
 | 
						|
  for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
 | 
						|
    if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
 | 
						|
      Str[Index - 1] = 0;
 | 
						|
    } else {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the formatted IP address into the binary IP address.
 | 
						|
 | 
						|
  @param[in]   Str               The UNICODE string.
 | 
						|
  @param[in]   IpMode            Indicates whether the IP address is v4 or v6.
 | 
						|
  @param[out]  Ip                The storage to return the ASCII string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The binary IP address is returned in Ip.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The IP string is malformatted or IpMode is
 | 
						|
                                 invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiAsciiStrToIp (
 | 
						|
  IN  CHAR8             *Str,
 | 
						|
  IN  UINT8             IpMode,
 | 
						|
  OUT EFI_IP_ADDRESS    *Ip
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
 | 
						|
  if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
 | 
						|
    return NetLibAsciiStrToIp4 (Str, &Ip->v4);
 | 
						|
 | 
						|
  } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
 | 
						|
    return NetLibAsciiStrToIp6 (Str, &Ip->v6);
 | 
						|
 | 
						|
  } else if (IpMode == IP_MODE_AUTOCONFIG) {
 | 
						|
    Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    return NetLibAsciiStrToIp6 (Str, &Ip->v6);
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the mac address into a hexadecimal encoded "-" seperated string.
 | 
						|
 | 
						|
  @param[in]  Mac     The mac address.
 | 
						|
  @param[in]  Len     Length in bytes of the mac address.
 | 
						|
  @param[in]  VlanId  VLAN ID of the network device.
 | 
						|
  @param[out] Str     The storage to return the mac string.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiMacAddrToStr (
 | 
						|
  IN  EFI_MAC_ADDRESS  *Mac,
 | 
						|
  IN  UINT32           Len,
 | 
						|
  IN  UINT16           VlanId,
 | 
						|
  OUT CHAR16           *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  Index;
 | 
						|
  CHAR16  *String;
 | 
						|
 | 
						|
  for (Index = 0; Index < Len; Index++) {
 | 
						|
    Str[3 * Index]      = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
 | 
						|
    Str[3 * Index + 1]  = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
 | 
						|
    Str[3 * Index + 2]  = L':';
 | 
						|
  }
 | 
						|
 | 
						|
  String = &Str[3 * Index - 1] ;
 | 
						|
  if (VlanId != 0) {
 | 
						|
    String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
 | 
						|
  }
 | 
						|
 | 
						|
  *String = L'\0';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the binary encoded buffer into a hexadecimal encoded string.
 | 
						|
 | 
						|
  @param[in]       BinBuffer   The buffer containing the binary data.
 | 
						|
  @param[in]       BinLength   Length of the binary buffer.
 | 
						|
  @param[in, out]  HexStr      Pointer to the string.
 | 
						|
  @param[in, out]  HexLength   The length of the string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The binary data is converted to the hexadecimal string 
 | 
						|
                               and the length of the string is updated.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL The string is too small.
 | 
						|
  @retval EFI_INVALID_PARAMETER The IP string is malformatted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiBinToHex (
 | 
						|
  IN     UINT8  *BinBuffer,
 | 
						|
  IN     UINT32 BinLength,
 | 
						|
  IN OUT CHAR8  *HexStr,
 | 
						|
  IN OUT UINT32 *HexLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN Index;
 | 
						|
 | 
						|
  if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((*HexLength) - 3) < BinLength * 2) {
 | 
						|
    *HexLength = BinLength * 2 + 3;
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  *HexLength = BinLength * 2 + 3;
 | 
						|
  //
 | 
						|
  // Prefix for Hex String.
 | 
						|
  //
 | 
						|
  HexStr[0] = '0';
 | 
						|
  HexStr[1] = 'x';
 | 
						|
 | 
						|
  for (Index = 0; Index < BinLength; Index++) {
 | 
						|
    HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
 | 
						|
    HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];
 | 
						|
  }
 | 
						|
 | 
						|
  HexStr[Index * 2 + 2] = '\0';
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the hexadecimal string into a binary encoded buffer.
 | 
						|
 | 
						|
  @param[in, out]  BinBuffer   The binary buffer.
 | 
						|
  @param[in, out]  BinLength   Length of the binary buffer.
 | 
						|
  @param[in]       HexStr      The hexadecimal string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The hexadecimal string is converted into a binary
 | 
						|
                               encoded buffer.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiHexToBin (
 | 
						|
  IN OUT UINT8  *BinBuffer,
 | 
						|
  IN OUT UINT32 *BinLength,
 | 
						|
  IN     CHAR8  *HexStr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index;
 | 
						|
  UINTN   Length;
 | 
						|
  UINT8   Digit;
 | 
						|
  CHAR8   TemStr[2];
 | 
						|
  
 | 
						|
  ZeroMem (TemStr, sizeof (TemStr));
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out how many hex characters the string has.
 | 
						|
  //
 | 
						|
  if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
 | 
						|
    HexStr += 2;
 | 
						|
  }
 | 
						|
  
 | 
						|
  Length = AsciiStrLen (HexStr);
 | 
						|
 | 
						|
  for (Index = 0; Index < Length; Index ++) {
 | 
						|
    TemStr[0] = HexStr[Index];
 | 
						|
    Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
 | 
						|
    if (Digit == 0 && TemStr[0] != '0') {
 | 
						|
      //
 | 
						|
      // Invalid Lun Char.
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if ((Index & 1) == 0) {
 | 
						|
      BinBuffer [Index/2] = Digit;
 | 
						|
    } else {
 | 
						|
      BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  *BinLength = (UINT32) ((Index + 1)/2);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the decimal-constant string or hex-constant string into a numerical value.
 | 
						|
 | 
						|
  @param[in] Str                    String in decimal or hex.
 | 
						|
 | 
						|
  @return The numerical value.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
IScsiNetNtoi (
 | 
						|
  IN     CHAR8  *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
 | 
						|
    Str += 2;
 | 
						|
 | 
						|
    return AsciiStrHexToUintn (Str);
 | 
						|
  }
 | 
						|
 | 
						|
  return AsciiStrDecimalToUintn (Str);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Generate random numbers.
 | 
						|
 | 
						|
  @param[in, out]  Rand       The buffer to contain random numbers.
 | 
						|
  @param[in]       RandLength The length of the Rand buffer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiGenRandom (
 | 
						|
  IN OUT UINT8  *Rand,
 | 
						|
  IN     UINTN  RandLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  Random;
 | 
						|
 | 
						|
  while (RandLength > 0) {
 | 
						|
    Random  = NET_RANDOM (NetRandomInitSeed ());
 | 
						|
    *Rand++ = (UINT8) (Random);
 | 
						|
    RandLength--;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Record the NIC info in global structure.
 | 
						|
 | 
						|
  @param[in]  Controller         The handle of the controller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The operation is completed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Do not have sufficient resources to finish this
 | 
						|
                                 operation.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiAddNic (
 | 
						|
  IN EFI_HANDLE  Controller
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  ISCSI_NIC_INFO              *NicInfo;
 | 
						|
  LIST_ENTRY                  *Entry;
 | 
						|
  EFI_MAC_ADDRESS             MacAddr;
 | 
						|
  UINTN                       HwAddressSize;
 | 
						|
  UINT16                      VlanId;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get MAC address of this network device.
 | 
						|
  //
 | 
						|
  Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get VLAN ID of this network device.
 | 
						|
  //
 | 
						|
  VlanId = NetLibGetVlanId (Controller);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether the NIC info already exists. Return directly if so.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
 | 
						|
    NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
 | 
						|
    if (NicInfo->HwAddressSize == HwAddressSize &&
 | 
						|
        CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
 | 
						|
        NicInfo->VlanId == VlanId) {
 | 
						|
      mPrivate->CurrentNic = NicInfo->NicIndex;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mPrivate->MaxNic < NicInfo->NicIndex) {
 | 
						|
      mPrivate->MaxNic = NicInfo->NicIndex;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Record the NIC info in private structure.
 | 
						|
  //
 | 
						|
  NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
 | 
						|
  if (NicInfo == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
 | 
						|
  NicInfo->HwAddressSize  = (UINT32) HwAddressSize;
 | 
						|
  NicInfo->VlanId         = VlanId;
 | 
						|
  NicInfo->NicIndex       = (UINT8) (mPrivate->MaxNic + 1);
 | 
						|
  mPrivate->MaxNic        = NicInfo->NicIndex;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the PCI location.
 | 
						|
  //
 | 
						|
  IScsiGetNICPciLocation (
 | 
						|
    Controller,
 | 
						|
    &NicInfo->BusNumber,
 | 
						|
    &NicInfo->DeviceNumber,
 | 
						|
    &NicInfo->FunctionNumber
 | 
						|
    );
 | 
						|
 | 
						|
  InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
 | 
						|
  mPrivate->NicCount++;
 | 
						|
 | 
						|
  mPrivate->CurrentNic = NicInfo->NicIndex;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Delete the recorded NIC info from global structure. Also delete corresponding
 | 
						|
  attempts.
 | 
						|
 | 
						|
  @param[in]  Controller         The handle of the controller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The operation is completed.
 | 
						|
  @retval EFI_NOT_FOUND          The NIC info to be deleted is not recorded.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiRemoveNic (
 | 
						|
  IN EFI_HANDLE  Controller
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  ISCSI_NIC_INFO              *NicInfo;
 | 
						|
  LIST_ENTRY                  *Entry;
 | 
						|
  LIST_ENTRY                  *NextEntry;
 | 
						|
  ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
 | 
						|
  ISCSI_NIC_INFO              *ThisNic;
 | 
						|
  EFI_MAC_ADDRESS             MacAddr;
 | 
						|
  UINTN                       HwAddressSize;
 | 
						|
  UINT16                      VlanId;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get MAC address of this network device.
 | 
						|
  //
 | 
						|
  Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get VLAN ID of this network device.
 | 
						|
  //
 | 
						|
  VlanId = NetLibGetVlanId (Controller);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether the NIC information exists.
 | 
						|
  //
 | 
						|
  ThisNic = NULL;
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
 | 
						|
    NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
 | 
						|
    if (NicInfo->HwAddressSize == HwAddressSize &&
 | 
						|
        CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
 | 
						|
        NicInfo->VlanId == VlanId) {
 | 
						|
 | 
						|
      ThisNic = NicInfo;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ThisNic == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  mPrivate->CurrentNic = ThisNic->NicIndex;
 | 
						|
 | 
						|
  RemoveEntryList (&ThisNic->Link);
 | 
						|
  FreePool (ThisNic);
 | 
						|
  mPrivate->NicCount--;
 | 
						|
 | 
						|
  //
 | 
						|
  // Remove all attempts related to this NIC.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
 | 
						|
    AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
 | 
						|
    if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
 | 
						|
      RemoveEntryList (&AttemptConfigData->Link);
 | 
						|
      mPrivate->AttemptCount--;
 | 
						|
 | 
						|
      if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
 | 
						|
        if (--mPrivate->MpioCount == 0) {
 | 
						|
          mPrivate->EnableMpio = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
 | 
						|
          mPrivate->Krb5MpioCount--;
 | 
						|
        }
 | 
						|
 | 
						|
      } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
 | 
						|
        mPrivate->SinglePathCount--;
 | 
						|
 | 
						|
        if (mPrivate->ValidSinglePathCount > 0) {
 | 
						|
          mPrivate->ValidSinglePathCount--;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (AttemptConfigData);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Free attempt is created but not saved to system.
 | 
						|
  //
 | 
						|
  if (mPrivate->NewAttempt != NULL) {
 | 
						|
    FreePool (mPrivate->NewAttempt);
 | 
						|
    mPrivate->NewAttempt = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the recorded NIC info from global structure by the Index.
 | 
						|
 | 
						|
  @param[in]  NicIndex          The index indicates the position of NIC info.
 | 
						|
 | 
						|
  @return Pointer to the NIC info, or NULL if not found.
 | 
						|
 | 
						|
**/
 | 
						|
ISCSI_NIC_INFO *
 | 
						|
IScsiGetNicInfoByIndex (
 | 
						|
  IN UINT8      NicIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY        *Entry;
 | 
						|
  ISCSI_NIC_INFO    *NicInfo;
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
 | 
						|
    NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
 | 
						|
    if (NicInfo->NicIndex == NicIndex) {
 | 
						|
      return NicInfo;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the NIC's PCI location and return it accroding to the composited
 | 
						|
  format defined in iSCSI Boot Firmware Table.
 | 
						|
 | 
						|
  @param[in]   Controller        The handle of the controller.
 | 
						|
  @param[out]  Bus               The bus number.
 | 
						|
  @param[out]  Device            The device number.
 | 
						|
  @param[out]  Function          The function number.
 | 
						|
 | 
						|
  @return      The composited representation of the NIC PCI location.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
IScsiGetNICPciLocation (
 | 
						|
  IN EFI_HANDLE  Controller,
 | 
						|
  OUT UINTN      *Bus,
 | 
						|
  OUT UINTN      *Device,
 | 
						|
  OUT UINTN      *Function
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_HANDLE                PciIoHandle;
 | 
						|
  EFI_PCI_IO_PROTOCOL       *PciIo;
 | 
						|
  UINTN                     Segment;
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &DevicePath
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateDevicePath (
 | 
						|
                  &gEfiPciIoProtocolGuid,
 | 
						|
                  &DevicePath,
 | 
						|
                  &PciIoHandle
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
 | 
						|
  buffer, and the size of the buffer. If failure, return NULL.
 | 
						|
 | 
						|
  @param[in]   Name                   String part of EFI variable name.
 | 
						|
  @param[in]   VendorGuid             GUID part of EFI variable name.
 | 
						|
  @param[out]  VariableSize           Returns the size of the EFI variable that was read.
 | 
						|
 | 
						|
  @return Dynamically allocated memory that contains a copy of the EFI variable.
 | 
						|
  @return Caller is responsible freeing the buffer.
 | 
						|
  @retval NULL                   Variable was not read.
 | 
						|
 | 
						|
**/
 | 
						|
VOID *
 | 
						|
IScsiGetVariableAndSize (
 | 
						|
  IN  CHAR16              *Name,
 | 
						|
  IN  EFI_GUID            *VendorGuid,
 | 
						|
  OUT UINTN               *VariableSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINTN       BufferSize;
 | 
						|
  VOID        *Buffer;
 | 
						|
 | 
						|
  Buffer = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Pass in a zero size buffer to find the required buffer size.
 | 
						|
  //
 | 
						|
  BufferSize  = 0;
 | 
						|
  Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
 | 
						|
  if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    //
 | 
						|
    // Allocate the buffer to return
 | 
						|
    //
 | 
						|
    Buffer = AllocateZeroPool (BufferSize);
 | 
						|
    if (Buffer == NULL) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Read variable into the allocated buffer.
 | 
						|
    //
 | 
						|
    Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      BufferSize = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *VariableSize = BufferSize;
 | 
						|
  return Buffer;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Create the iSCSI driver data.
 | 
						|
 | 
						|
  @param[in] Image      The handle of the driver image.
 | 
						|
  @param[in] Controller The handle of the controller.
 | 
						|
 | 
						|
  @return The iSCSI driver data created.
 | 
						|
  @retval NULL Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
ISCSI_DRIVER_DATA *
 | 
						|
IScsiCreateDriverData (
 | 
						|
  IN EFI_HANDLE  Image,
 | 
						|
  IN EFI_HANDLE  Controller
 | 
						|
  )
 | 
						|
{
 | 
						|
  ISCSI_DRIVER_DATA *Private;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
 | 
						|
  Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
 | 
						|
  if (Private == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Private->Signature  = ISCSI_DRIVER_DATA_SIGNATURE;
 | 
						|
  Private->Image      = Image;
 | 
						|
  Private->Controller = Controller;
 | 
						|
  Private->Session    = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create an event to be signaled when the BS to RT transition is triggerd so
 | 
						|
  // as to abort the iSCSI session.
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEventEx (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  IScsiOnExitBootService,
 | 
						|
                  Private,
 | 
						|
                  &gEfiEventExitBootServicesGuid,
 | 
						|
                  &Private->ExitBootServiceEvent
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (Private);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Private->ExtScsiPassThruHandle = NULL;
 | 
						|
  CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
 | 
						|
 | 
						|
  //
 | 
						|
  // 0 is designated to the TargetId, so use another value for the AdapterId.
 | 
						|
  //
 | 
						|
  Private->ExtScsiPassThruMode.AdapterId  = 2;
 | 
						|
  Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
 | 
						|
  Private->ExtScsiPassThruMode.IoAlign    = 4;
 | 
						|
  Private->IScsiExtScsiPassThru.Mode      = &Private->ExtScsiPassThruMode;
 | 
						|
 | 
						|
  return Private;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Clean the iSCSI driver data.
 | 
						|
 | 
						|
  @param[in]  Private The iSCSI driver data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiCleanDriverData (
 | 
						|
  IN ISCSI_DRIVER_DATA  *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
 | 
						|
  if (Private->DevicePath != NULL) {
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           Private->ExtScsiPassThruHandle,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           Private->DevicePath
 | 
						|
           );
 | 
						|
 | 
						|
    FreePool (Private->DevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->ExtScsiPassThruHandle != NULL) {
 | 
						|
    Status = gBS->UninstallProtocolInterface (
 | 
						|
                    Private->ExtScsiPassThruHandle,
 | 
						|
                    &gEfiExtScsiPassThruProtocolGuid,
 | 
						|
                    &Private->IScsiExtScsiPassThru
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      mPrivate->OneSessionEstablished = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseEvent (Private->ExitBootServiceEvent);
 | 
						|
 | 
						|
  FreePool (Private);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the various configuration data.
 | 
						|
 | 
						|
  @param[in]  Private   The iSCSI driver data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The configuration data is retrieved.
 | 
						|
  @retval EFI_NOT_FOUND          This iSCSI driver is not configured yet.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiGetConfigData (
 | 
						|
  IN ISCSI_DRIVER_DATA  *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
 | 
						|
  UINTN                       Index;
 | 
						|
  ISCSI_NIC_INFO              *NicInfo;
 | 
						|
  ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
 | 
						|
  ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
 | 
						|
  UINT8                       *AttemptConfigOrder;
 | 
						|
  UINTN                       AttemptConfigOrderSize;
 | 
						|
  CHAR16                      IScsiMode[64];
 | 
						|
  CHAR16                      IpMode[64];
 | 
						|
 | 
						|
  //
 | 
						|
  // There should be at least one attempt configured.
 | 
						|
  //
 | 
						|
  AttemptConfigOrder = IScsiGetVariableAndSize (
 | 
						|
                         L"AttemptOrder",
 | 
						|
                         &gIScsiConfigGuid,
 | 
						|
                         &AttemptConfigOrderSize
 | 
						|
                         );
 | 
						|
  if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the iSCSI Initiator Name.
 | 
						|
  //
 | 
						|
  mPrivate->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;
 | 
						|
  Status = gIScsiInitiatorName.Get (
 | 
						|
                                 &gIScsiInitiatorName,
 | 
						|
                                 &mPrivate->InitiatorNameLength,
 | 
						|
                                 mPrivate->InitiatorName
 | 
						|
                                 );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the normal configuration.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
 | 
						|
 | 
						|
    //
 | 
						|
    // Check whether the attempt exists in AttemptConfig.
 | 
						|
    //
 | 
						|
    AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);    
 | 
						|
    if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
 | 
						|
      continue;
 | 
						|
    } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
 | 
						|
      //
 | 
						|
      // Check the autoconfig path to see whether it should be retried.
 | 
						|
      //
 | 
						|
      if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
 | 
						|
          AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {
 | 
						|
        if (mPrivate->Ipv6Flag &&
 | 
						|
            AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
 | 
						|
          //
 | 
						|
          // Autoconfigure for IP6 already attempted but failed. Do not try again.
 | 
						|
          //
 | 
						|
          continue;
 | 
						|
        } else if (!mPrivate->Ipv6Flag &&
 | 
						|
                   AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
 | 
						|
          //
 | 
						|
          // Autoconfigure for IP4  already attempted but failed. Do not try again.
 | 
						|
          //
 | 
						|
          continue;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Try another approach for this autoconfigure path.
 | 
						|
          //
 | 
						|
          AttemptTmp->AutoConfigureMode =
 | 
						|
            (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
 | 
						|
          AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
 | 
						|
          AttemptTmp->SessionConfigData.TargetInfoFromDhcp    = TRUE;
 | 
						|
          AttemptTmp->DhcpSuccess                             = FALSE;
 | 
						|
 | 
						|
          //
 | 
						|
          // Get some information from the dhcp server.
 | 
						|
          //
 | 
						|
          if (!mPrivate->Ipv6Flag) {
 | 
						|
            Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
 | 
						|
            if (!EFI_ERROR (Status)) {
 | 
						|
              AttemptTmp->DhcpSuccess = TRUE;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
 | 
						|
            if (!EFI_ERROR (Status)) {
 | 
						|
              AttemptTmp->DhcpSuccess = TRUE;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Refresh the state of this attempt to NVR.
 | 
						|
          //
 | 
						|
          AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
 | 
						|
          UnicodeSPrint (
 | 
						|
            mPrivate->PortString,
 | 
						|
            (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
 | 
						|
            L"%s%d",
 | 
						|
            MacString,
 | 
						|
            (UINTN) AttemptTmp->AttemptConfigIndex
 | 
						|
            );
 | 
						|
 | 
						|
          gRT->SetVariable (
 | 
						|
                 mPrivate->PortString,
 | 
						|
                 &gEfiIScsiInitiatorNameProtocolGuid,
 | 
						|
                 ISCSI_CONFIG_VAR_ATTR,
 | 
						|
                 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
 | 
						|
                 AttemptTmp
 | 
						|
                 );
 | 
						|
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
 | 
						|
        //
 | 
						|
        // Get DHCP information for already added, but failed, attempt.
 | 
						|
        //
 | 
						|
        AttemptTmp->DhcpSuccess = FALSE;
 | 
						|
        if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
 | 
						|
          Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
 | 
						|
          if (!EFI_ERROR (Status)) {
 | 
						|
            AttemptTmp->DhcpSuccess = TRUE;
 | 
						|
          }
 | 
						|
        } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
 | 
						|
          Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
 | 
						|
          if (!EFI_ERROR (Status)) {
 | 
						|
            AttemptTmp->DhcpSuccess = TRUE;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Refresh the state of this attempt to NVR.
 | 
						|
        //
 | 
						|
        AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
 | 
						|
        UnicodeSPrint (
 | 
						|
          mPrivate->PortString,
 | 
						|
          (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
 | 
						|
          L"%s%d",
 | 
						|
          MacString,
 | 
						|
          (UINTN) AttemptTmp->AttemptConfigIndex
 | 
						|
          );
 | 
						|
 | 
						|
        gRT->SetVariable (
 | 
						|
               mPrivate->PortString,
 | 
						|
               &gEfiIScsiInitiatorNameProtocolGuid,
 | 
						|
               ISCSI_CONFIG_VAR_ATTR,
 | 
						|
               sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
 | 
						|
               AttemptTmp
 | 
						|
               );
 | 
						|
 | 
						|
        continue;
 | 
						|
 | 
						|
      } else {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // This attempt does not exist in AttemptConfig. Try to add a new one.
 | 
						|
    //
 | 
						|
 | 
						|
    NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
 | 
						|
    ASSERT (NicInfo != NULL);
 | 
						|
    IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
 | 
						|
    UnicodeSPrint (
 | 
						|
      mPrivate->PortString,
 | 
						|
      (UINTN) 128,
 | 
						|
      L"%s%d",
 | 
						|
      MacString,
 | 
						|
      (UINTN) AttemptConfigOrder[Index]
 | 
						|
      );
 | 
						|
 | 
						|
    AttemptConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) GetVariable (
 | 
						|
                                                          mPrivate->PortString,
 | 
						|
                                                          &gEfiIScsiInitiatorNameProtocolGuid
 | 
						|
                                                          );
 | 
						|
 | 
						|
    if (AttemptConfigData == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
 | 
						|
 | 
						|
    AttemptConfigData->NicIndex      = NicInfo->NicIndex;
 | 
						|
    AttemptConfigData->DhcpSuccess   = FALSE;
 | 
						|
    AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
 | 
						|
    AttemptConfigData->ValidPath     = FALSE;
 | 
						|
 | 
						|
    if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
 | 
						|
      AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
 | 
						|
      AttemptConfigData->SessionConfigData.TargetInfoFromDhcp    = TRUE;
 | 
						|
 | 
						|
      AttemptConfigData->AutoConfigureMode =
 | 
						|
        (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Get some information from dhcp server.
 | 
						|
    //
 | 
						|
    if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
 | 
						|
        AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
 | 
						|
 | 
						|
      if (!mPrivate->Ipv6Flag &&
 | 
						|
          (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
 | 
						|
           AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
 | 
						|
        Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          AttemptConfigData->DhcpSuccess = TRUE;
 | 
						|
        }
 | 
						|
      } else if (mPrivate->Ipv6Flag &&
 | 
						|
                (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
 | 
						|
                 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
 | 
						|
        Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          AttemptConfigData->DhcpSuccess = TRUE;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Refresh the state of this attempt to NVR.
 | 
						|
      //
 | 
						|
      AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
 | 
						|
      UnicodeSPrint (
 | 
						|
        mPrivate->PortString,
 | 
						|
        (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
 | 
						|
        L"%s%d",
 | 
						|
        MacString,
 | 
						|
        (UINTN) AttemptConfigData->AttemptConfigIndex
 | 
						|
        );
 | 
						|
 | 
						|
      gRT->SetVariable (
 | 
						|
             mPrivate->PortString,
 | 
						|
             &gEfiIScsiInitiatorNameProtocolGuid,
 | 
						|
             ISCSI_CONFIG_VAR_ATTR,
 | 
						|
             sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
 | 
						|
             AttemptConfigData
 | 
						|
             );
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Update Attempt Help Info.
 | 
						|
    //
 | 
						|
 | 
						|
    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
 | 
						|
      UnicodeSPrint (IScsiMode, 64, L"Disabled");
 | 
						|
    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
 | 
						|
      UnicodeSPrint (IScsiMode, 64, L"Enabled");
 | 
						|
    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
 | 
						|
      UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
 | 
						|
    }
 | 
						|
 | 
						|
    if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
 | 
						|
      UnicodeSPrint (IpMode, 64, L"IP4");
 | 
						|
    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
 | 
						|
      UnicodeSPrint (IpMode, 64, L"IP6");
 | 
						|
    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
 | 
						|
      UnicodeSPrint (IpMode, 64, L"Autoconfigure");
 | 
						|
    }
 | 
						|
 | 
						|
    UnicodeSPrint (
 | 
						|
      mPrivate->PortString,
 | 
						|
      (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
 | 
						|
      L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
 | 
						|
      MacString,
 | 
						|
      NicInfo->BusNumber,
 | 
						|
      NicInfo->DeviceNumber,
 | 
						|
      NicInfo->FunctionNumber,
 | 
						|
      IScsiMode,
 | 
						|
      IpMode
 | 
						|
      );
 | 
						|
 | 
						|
    AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
 | 
						|
                                                 mCallbackInfo->RegisteredHandle,
 | 
						|
                                                 0,
 | 
						|
                                                 mPrivate->PortString,
 | 
						|
                                                 NULL
 | 
						|
                                                 );
 | 
						|
    ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
 | 
						|
 | 
						|
    //
 | 
						|
    // Record the attempt in global link list.
 | 
						|
    //
 | 
						|
    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
 | 
						|
    mPrivate->AttemptCount++;
 | 
						|
 | 
						|
    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
 | 
						|
      mPrivate->MpioCount++;
 | 
						|
      mPrivate->EnableMpio = TRUE;
 | 
						|
 | 
						|
      if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
 | 
						|
        mPrivate->Krb5MpioCount++;
 | 
						|
      }
 | 
						|
    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
 | 
						|
      mPrivate->SinglePathCount++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Reorder the AttemptConfig by the configured order.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
 | 
						|
    AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
 | 
						|
    if (AttemptConfigData == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    RemoveEntryList (&AttemptConfigData->Link);
 | 
						|
    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the Main Form.
 | 
						|
  //
 | 
						|
  IScsiConfigUpdateAttempt ();
 | 
						|
 | 
						|
  FreePool (AttemptConfigOrder);
 | 
						|
 | 
						|
  //
 | 
						|
  //  There should be at least one attempt configuration.
 | 
						|
  //
 | 
						|
  if (!mPrivate->EnableMpio) {
 | 
						|
    if (mPrivate->SinglePathCount == 0) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
    mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the device path of the iSCSI tcp connection and update it.
 | 
						|
 | 
						|
  @param  Session                The iSCSI session.
 | 
						|
 | 
						|
  @return The updated device path.
 | 
						|
  @retval NULL Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_DEVICE_PATH_PROTOCOL *
 | 
						|
IScsiGetTcpConnDevicePath (
 | 
						|
  IN ISCSI_SESSION      *Session
 | 
						|
  )
 | 
						|
{
 | 
						|
  ISCSI_CONNECTION          *Conn;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEV_PATH              *DPathNode;
 | 
						|
 | 
						|
  if (Session->State != SESSION_STATE_LOGGED_IN) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Conn = NET_LIST_USER_STRUCT_S (
 | 
						|
           Session->Conns.ForwardLink,
 | 
						|
           ISCSI_CONNECTION,
 | 
						|
           Link,
 | 
						|
           ISCSI_CONNECTION_SIGNATURE
 | 
						|
           );
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  Conn->TcpIo.Handle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &DevicePath
 | 
						|
                  );  
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Duplicate it.
 | 
						|
  //
 | 
						|
  DevicePath  = DuplicateDevicePath (DevicePath);
 | 
						|
  if (DevicePath == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  DPathNode   = (EFI_DEV_PATH *) DevicePath;
 | 
						|
 | 
						|
  while (!IsDevicePathEnd (&DPathNode->DevPath)) {
 | 
						|
    if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
 | 
						|
      if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
 | 
						|
        DPathNode->Ipv4.LocalPort       = 0;
 | 
						|
 | 
						|
        DPathNode->Ipv4.StaticIpAddress = 
 | 
						|
          (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
 | 
						|
 | 
						|
        IP4_COPY_ADDRESS (
 | 
						|
          &DPathNode->Ipv4.GatewayIpAddress,
 | 
						|
          &Session->ConfigData->SessionConfigData.Gateway
 | 
						|
          );
 | 
						|
 | 
						|
        IP4_COPY_ADDRESS (
 | 
						|
          &DPathNode->Ipv4.SubnetMask,
 | 
						|
          &Session->ConfigData->SessionConfigData.SubnetMask
 | 
						|
          );
 | 
						|
        break;
 | 
						|
      } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
 | 
						|
        DPathNode->Ipv6.LocalPort       = 0;
 | 
						|
        DPathNode->Ipv6.IpAddressOrigin = 0;
 | 
						|
        DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;
 | 
						|
        ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
 | 
						|
  }
 | 
						|
 | 
						|
  return DevicePath;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Abort the session when the transition from BS to RT is initiated.
 | 
						|
 | 
						|
  @param[in]   Event  The event signaled.
 | 
						|
  @param[in]  Context The iSCSI driver data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
IScsiOnExitBootService (
 | 
						|
  IN EFI_EVENT  Event,
 | 
						|
  IN VOID       *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  ISCSI_DRIVER_DATA *Private;
 | 
						|
 | 
						|
  Private = (ISCSI_DRIVER_DATA *) Context;
 | 
						|
  gBS->CloseEvent (Private->ExitBootServiceEvent);
 | 
						|
 | 
						|
  if (Private->Session != NULL) {
 | 
						|
    IScsiSessionAbort (Private->Session);
 | 
						|
  }
 | 
						|
}
 |