From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c | 2565 +++++++++++++++++++++++++++++ 1 file changed, 2565 insertions(+) create mode 100644 roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c (limited to 'roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c') diff --git a/roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c b/roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c new file mode 100644 index 000000000..b8fef3ff6 --- /dev/null +++ b/roms/edk2/NetworkPkg/IScsiDxe/IScsiMisc.c @@ -0,0 +1,2565 @@ +/** @file + Miscellaneous routines for iSCSI driver. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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) { + CopyMem (TempStr, L"0-", sizeof (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); + } + // + // Remove the last '-' + // + ASSERT (StrLen(Str) >= 1); + 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 "-" separated 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--; + } +} + + +/** + Check whether UNDI protocol supports IPv6. + + @param[in] ControllerHandle Controller handle. + @param[in] Image Handle of the image. + @param[out] Ipv6Support TRUE if UNDI supports IPv6. + + @retval EFI_SUCCESS Get the result whether UNDI supports IPv6 by NII or AIP protocol successfully. + @retval EFI_NOT_FOUND Don't know whether UNDI supports IPv6 since NII or AIP is not available. + +**/ +EFI_STATUS +IScsiCheckIpv6Support ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE Image, + OUT BOOLEAN *Ipv6Support + ) +{ + EFI_HANDLE Handle; + EFI_ADAPTER_INFORMATION_PROTOCOL *Aip; + EFI_STATUS Status; + EFI_GUID *InfoTypesBuffer; + UINTN InfoTypeBufferCount; + UINTN TypeIndex; + BOOLEAN Supported; + VOID *InfoBlock; + UINTN InfoBlockSize; + + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; + + ASSERT (Ipv6Support != NULL); + + // + // Check whether the UNDI supports IPv6 by NII protocol. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Nii, + Image, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (Status == EFI_SUCCESS) { + *Ipv6Support = Nii->Ipv6Supported; + return EFI_SUCCESS; + } + + // + // Get the NIC handle by SNP protocol. + // + Handle = NetLibGetSnpHandle (ControllerHandle, NULL); + if (Handle == NULL) { + return EFI_NOT_FOUND; + } + + Aip = NULL; + Status = gBS->HandleProtocol ( + Handle, + &gEfiAdapterInformationProtocolGuid, + (VOID *) &Aip + ); + if (EFI_ERROR (Status) || Aip == NULL) { + return EFI_NOT_FOUND; + } + + InfoTypesBuffer = NULL; + InfoTypeBufferCount = 0; + Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount); + if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) { + FreePool (InfoTypesBuffer); + return EFI_NOT_FOUND; + } + + Supported = FALSE; + for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) { + if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoUndiIpv6SupportGuid)) { + Supported = TRUE; + break; + } + } + + FreePool (InfoTypesBuffer); + if (!Supported) { + return EFI_NOT_FOUND; + } + + // + // We now have adapter information block. + // + InfoBlock = NULL; + InfoBlockSize = 0; + Status = Aip->GetInformation (Aip, &gEfiAdapterInfoUndiIpv6SupportGuid, &InfoBlock, &InfoBlockSize); + if (EFI_ERROR (Status) || InfoBlock == NULL) { + FreePool (InfoBlock); + return EFI_NOT_FOUND; + } + + *Ipv6Support = ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) InfoBlock)->Ipv6Support; + FreePool (InfoBlock); + + return EFI_SUCCESS; +} + +/** + Record the NIC info in global structure. + + @param[in] Controller The handle of the controller. + @param[in] Image Handle of the image. + + @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, + IN EFI_HANDLE Image + ) +{ + 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; + + // + // Set IPv6 available flag. + // + Status = IScsiCheckIpv6Support (Controller, Image, &NicInfo->Ipv6Available); + if (EFI_ERROR (Status)) { + // + // Fail to get the data whether UNDI supports IPv6. + // Set default value to TRUE. + // + NicInfo->Ipv6Available = TRUE; + } + + 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; + + // + // Set IPv6 available flag. + // + Status = IScsiCheckIpv6Support (Controller, Image, &NicInfo->Ipv6Available); + if (EFI_ERROR (Status)) { + // + // Fail to get the data whether UNDI supports IPv6. + // Set default value to TRUE. + // + NicInfo->Ipv6Available = TRUE; + } + + // + // 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); + } + } + + return EFI_SUCCESS; +} + +/** + Create and initialize the Attempts. + + @param[in] AttemptNum The number of Attempts will be created. + + @retval EFI_SUCCESS The Attempts have been created successfully. + @retval Others Failed to create the Attempt. + +**/ +EFI_STATUS +IScsiCreateAttempts ( + IN UINTN AttemptNum +) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + ISCSI_SESSION_CONFIG_NVDATA *ConfigData; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINT8 *AttemptOrderTmp; + UINTN TotalNumber; + UINT8 Index; + EFI_STATUS Status; + + for (Index = 1; Index <= AttemptNum; Index ++) { + // + // Get the initialized attempt order. This is used to essure creating attempts by order. + // + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"InitialAttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + TotalNumber = AttemptConfigOrderSize / sizeof (UINT8); + if (TotalNumber == AttemptNum) { + Status = EFI_SUCCESS; + break; + } + TotalNumber++; + + // + // Append the new created attempt to the end. + // + AttemptOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8)); + if (AttemptOrderTmp == NULL) { + if (AttemptConfigOrder != NULL) { + FreePool (AttemptConfigOrder); + } + return EFI_OUT_OF_RESOURCES; + } + + if (AttemptConfigOrder != NULL) { + CopyMem (AttemptOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize); + FreePool (AttemptConfigOrder); + } + + AttemptOrderTmp[TotalNumber - 1] = Index; + AttemptConfigOrder = AttemptOrderTmp; + AttemptConfigOrderSize = TotalNumber * sizeof (UINT8); + + Status = gRT->SetVariable ( + L"InitialAttemptOrder", + &gIScsiConfigGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + AttemptConfigOrderSize, + AttemptConfigOrder + ); + FreePool (AttemptConfigOrder); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Failed to set 'InitialAttemptOrder' with Guid (%g): " + "%r\n", + __FUNCTION__, &gIScsiConfigGuid, Status)); + return Status; + } + + // + // Create new Attempt + // + AttemptConfigData = AllocateZeroPool (sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA)); + if (AttemptConfigData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ConfigData = &AttemptConfigData->SessionConfigData; + ConfigData->TargetPort = ISCSI_WELL_KNOWN_PORT; + ConfigData->ConnectTimeout = CONNECT_DEFAULT_TIMEOUT; + ConfigData->ConnectRetryCount = CONNECT_MIN_RETRY; + + AttemptConfigData->AuthenticationType = ISCSI_AUTH_TYPE_CHAP; + AttemptConfigData->AuthConfigData.CHAP.CHAPType = ISCSI_CHAP_UNI; + // + // Configure the Attempt index and set variable. + // + AttemptConfigData->AttemptConfigIndex = Index; + + // + // Set the attempt name according to the order. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (UINTN) AttemptConfigData->AttemptConfigIndex + ); + UnicodeStrToAsciiStrS (mPrivate->PortString, AttemptConfigData->AttemptName, ATTEMPT_NAME_SIZE); + + Status = gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + ISCSI_CONFIG_VAR_ATTR, + sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), + AttemptConfigData + ); + FreePool (AttemptConfigData); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Failed to set variable (mPrivate->PortString) with Guid (%g): " + "%r\n", + __FUNCTION__, &gEfiIScsiInitiatorNameProtocolGuid, Status)); + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Create the iSCSI configuration Keywords for each attempt. You can find the keywords + defined in the "x-UEFI-ns" namespace (http://www.uefi.org/confignamespace). + + @param[in] KeywordNum The number Sets of Keywords will be created. + + @retval EFI_SUCCESS The operation is completed. + @retval Others Failed to create the Keywords. + +**/ +EFI_STATUS +IScsiCreateKeywords ( + IN UINTN KeywordNum +) +{ + VOID *StartOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *EndLabel; + UINTN Index; + EFI_STRING_ID StringToken; + CHAR16 StringId[64]; + CHAR16 KeywordId[32]; + EFI_STATUS Status; + + Status = IScsiCreateOpCode ( + KEYWORD_ENTRY_LABEL, + &StartOpCodeHandle, + &StartLabel, + &EndOpCodeHandle, + &EndLabel + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 1; Index <= KeywordNum; Index ++) { + // + // Create iSCSIAttemptName Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_ATTEMPTT_NAME_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIAttemptName:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_ATTEMPT_NAME_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_ATTEMPT_NAME_VAR_OFFSET + ATTEMPT_NAME_SIZE * (Index - 1) * sizeof (CHAR16)), + StringToken, + StringToken, + EFI_IFR_FLAG_READ_ONLY, + 0, + 0, + ATTEMPT_NAME_SIZE, + NULL + ); + + // + // Create iSCSIBootEnable Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_MODE_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIBootEnable:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_BOOTENABLE_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_BOOTENABLE_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + EFI_IFR_NUMERIC_SIZE_1, + 0, + 2, + 0, + NULL + ); + + // + // Create iSCSIIpAddressType Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_IP_MODE_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIIpAddressType:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_ADDRESS_TYPE_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_ADDRESS_TYPE_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + EFI_IFR_NUMERIC_SIZE_1, + 0, + 2, + 0, + NULL + ); + + // + // Create iSCSIConnectRetry Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CONNECT_RETRY_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIConnectRetry:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CONNECT_RETRY_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CONNECT_RETRY_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + EFI_IFR_NUMERIC_SIZE_1, + 0, + 16, + 0, + NULL + ); + + // + // Create iSCSIConnectTimeout Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CONNECT_TIMEOUT_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIConnectTimeout:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CONNECT_TIMEOUT_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET + 2 * (Index - 1)), + StringToken, + StringToken, + 0, + EFI_IFR_NUMERIC_SIZE_2, + CONNECT_MIN_TIMEOUT, + CONNECT_MAX_TIMEOUT, + 0, + NULL + ); + + // + // Create ISID Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_ISID_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIISID:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_ISID_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_ISID_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + STRING_TOKEN (STR_ISCSI_ISID_HELP), + 0, + 0, + ISID_CONFIGURABLE_MIN_LEN, + ISID_CONFIGURABLE_STORAGE, + NULL + ); + + // + // Create iSCSIInitiatorInfoViaDHCP Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_VIA_DHCP_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorInfoViaDHCP:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_VIA_DHCP_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + 1, + 0, + NULL + ); + + // + // Create iSCSIInitiatorIpAddress Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_IP_ADDRESS_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorIpAddress:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_IP_ADDRESS_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + IP4_MIN_SIZE, + IP4_STR_MAX_SIZE, + NULL + ); + + // + // Create iSCSIInitiatorNetmask Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_NET_MASK_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorNetmask:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_NET_MASK_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + IP4_MIN_SIZE, + IP4_STR_MAX_SIZE, + NULL + ); + + // + // Create iSCSIInitiatorGateway Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_GATE_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorGateway:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_GATE_WAY_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + IP4_MIN_SIZE, + IP4_STR_MAX_SIZE, + NULL + ); + + // + // Create iSCSITargetInfoViaDHCP Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_VIA_DHCP_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetInfoViaDHCP:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_TARGET_VIA_DHCP_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + 1, + 0, + NULL + ); + + // + // Create iSCSITargetTcpPort Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_TCP_PORT_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetTcpPort:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_TARGET_TCP_PORT_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET + 2 * (Index - 1)), + StringToken, + StringToken, + 0, + EFI_IFR_NUMERIC_SIZE_2, + TARGET_PORT_MIN_NUM, + TARGET_PORT_MAX_NUM, + 0, + NULL + ); + + // + // Create iSCSITargetName Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_NAME_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetName:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_TARGET_NAME_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_TARGET_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + ISCSI_NAME_IFR_MIN_SIZE, + ISCSI_NAME_IFR_MAX_SIZE, + NULL + ); + + // + // Create iSCSITargetIpAddress Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_IP_ADDRESS_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetIpAddress:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_TARGET_IP_ADDRESS_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + IP_MIN_SIZE, + IP_STR_MAX_SIZE, + NULL + ); + + // + // Create iSCSILUN Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_LUN_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSILUN:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_LUN_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_LUN_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + LUN_MIN_SIZE, + LUN_MAX_SIZE, + NULL + ); + + // + // Create iSCSIAuthenticationMethod Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_AUTHENTICATION_METHOD_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIAuthenticationMethod:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_AUTHENTICATION_METHOD_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + 1, + 0, + NULL + ); + + // + // Create iSCSIChapType Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHARTYPE_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapType:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateNumericOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CHARTYPE_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CHARTYPE_VAR_OFFSET + (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + 1, + 0, + NULL + ); + + // + // Create iSCSIChapUsername Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_USER_NAME_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapUsername:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CHAR_USER_NAME_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CHAR_USER_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + ISCSI_CHAP_NAME_MAX_LEN, + NULL + ); + + // + // Create iSCSIChapSecret Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_SECRET_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapSecret:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CHAR_SECRET_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CHAR_SECRET_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + ISCSI_CHAP_SECRET_MIN_LEN, + ISCSI_CHAP_SECRET_MAX_LEN, + NULL + ); + + // + // Create iSCSIReverseChapUsername Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_REVERSE_USER_NAME_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIReverseChapUsername:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CHAR_REVERSE_USER_NAME_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + 0, + ISCSI_CHAP_NAME_MAX_LEN, + NULL + ); + + // + // Create iSCSIReverseChapSecret Keyword. + // + UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_REVERSE_SECRET_PROMPT%d", Index); + StringToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + StringId, + NULL + ); + UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIReverseChapSecret:%d", Index); + HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns"); + HiiCreateStringOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_CHAR_REVERSE_SECRET_QUESTION_ID + (Index - 1)), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)), + StringToken, + StringToken, + 0, + 0, + ISCSI_CHAP_SECRET_MIN_LEN, + ISCSI_CHAP_SECRET_MAX_LEN, + NULL + ); + } + + Status = HiiUpdateForm ( + mCallbackInfo->RegisteredHandle, // HII handle + &gIScsiConfigGuid, // Formset GUID + FORMID_ATTEMPT_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return Status; +} + +/** + + Free the attempt configure data variable. + +**/ +VOID +IScsiCleanAttemptVariable ( + IN VOID +) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINTN Index; + + // + // Get the initialized attempt order. + // + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"InitialAttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) { + return; + } + + for (Index = 1; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + Index + ); + + GetVariable2 ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptConfigData, + NULL + ); + + if (AttemptConfigData != NULL) { + gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + 0, + 0, + NULL + ); + } + } + return; +} + +/** + 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 according 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. + + @retval EFI_SUCCESS The clean operation is successful. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +IScsiCleanDriverData ( + IN ISCSI_DRIVER_DATA *Private + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (Private->DevicePath != NULL) { + Status = gBS->UninstallProtocolInterface ( + Private->ExtScsiPassThruHandle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath + ); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + FreePool (Private->DevicePath); + } + + if (Private->ExtScsiPassThruHandle != NULL) { + Status = gBS->UninstallProtocolInterface ( + Private->ExtScsiPassThruHandle, + &gEfiExtScsiPassThruProtocolGuid, + &Private->IScsiExtScsiPassThru + ); + if (!EFI_ERROR (Status)) { + mPrivate->OneSessionEstablished = FALSE; + } + } + +EXIT: + if (Private->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Private->ExitBootServiceEvent); + } + + mCallbackInfo->Current = NULL; + + FreePool (Private); + return Status; +} + +/** + Check wheather the Controller handle is configured to use DHCP protocol. + + @param[in] Controller The handle of the controller. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval TRUE The handle of the controller need the Dhcp protocol. + @retval FALSE The handle of the controller does not need the Dhcp protocol. + +**/ +BOOLEAN +IScsiDhcpIsConfigured ( + IN EFI_HANDLE Controller, + IN UINT8 IpVersion + ) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINTN Index; + EFI_STATUS Status; + EFI_MAC_ADDRESS MacAddr; + UINTN HwAddressSize; + UINT16 VlanId; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 AttemptMacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE]; + + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) { + return FALSE; + } + + // + // Get MAC address of this network device. + // + Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize); + if(EFI_ERROR (Status)) { + return FALSE; + } + // + // Get VLAN ID of this network device. + // + VlanId = NetLibGetVlanId (Controller); + IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString); + + for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { + UnicodeSPrint ( + AttemptName, + (UINTN) 128, + L"Attempt %d", + (UINTN) AttemptConfigOrder[Index] + ); + Status = GetVariable2 ( + AttemptName, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptTmp, + NULL + ); + if(AttemptTmp == NULL || EFI_ERROR (Status)) { + continue; + } + + ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex); + + if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) { + FreePool (AttemptTmp); + continue; + } + + if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG && + AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) { + FreePool (AttemptTmp); + continue; + } + + AsciiStrToUnicodeStrS (AttemptTmp->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0])); + + if (AttemptTmp->Actived == ISCSI_ACTIVE_DISABLED || StrCmp (MacString, AttemptMacString)) { + continue; + } + + if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG || + AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE || + AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) { + FreePool (AttemptTmp); + FreePool (AttemptConfigOrder); + return TRUE; + } + + FreePool (AttemptTmp); + } + + FreePool (AttemptConfigOrder); + return FALSE; +} + +/** + Check whether the Controller handle is configured to use DNS protocol. + + @param[in] Controller The handle of the controller. + + @retval TRUE The handle of the controller need the Dns protocol. + @retval FALSE The handle of the controller does not need the Dns protocol. + +**/ +BOOLEAN +IScsiDnsIsConfigured ( + IN EFI_HANDLE Controller + ) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINTN Index; + EFI_STATUS Status; + EFI_MAC_ADDRESS MacAddr; + UINTN HwAddressSize; + UINT16 VlanId; + CHAR16 AttemptMacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE]; + + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) { + return FALSE; + } + + // + // Get MAC address of this network device. + // + Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize); + if(EFI_ERROR (Status)) { + return FALSE; + } + // + // Get VLAN ID of this network device. + // + VlanId = NetLibGetVlanId (Controller); + IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString); + + for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { + UnicodeSPrint ( + AttemptName, + (UINTN) 128, + L"Attempt %d", + (UINTN) AttemptConfigOrder[Index] + ); + + Status = GetVariable2 ( + AttemptName, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptTmp, + NULL + ); + if(AttemptTmp == NULL || EFI_ERROR (Status)) { + continue; + } + + ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex); + + AsciiStrToUnicodeStrS (AttemptTmp->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0])); + + if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED || StrCmp (MacString, AttemptMacString)) { + FreePool (AttemptTmp); + continue; + } + + if (AttemptTmp->SessionConfigData.DnsMode || AttemptTmp->SessionConfigData.TargetInfoFromDhcp) { + FreePool (AttemptTmp); + FreePool (AttemptConfigOrder); + return TRUE; + } else { + FreePool (AttemptTmp); + continue; + } + + } + + FreePool (AttemptConfigOrder); + return FALSE; + +} + +/** + 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. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + +**/ +EFI_STATUS +IScsiGetConfigData ( + IN ISCSI_DRIVER_DATA *Private + ) +{ + EFI_STATUS Status; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 AttemptMacString[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->AutoConfigureSuccess) { + 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. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (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 && + AttemptTmp->NicIndex == mPrivate->CurrentNic) { + // + // If the attempt associates with the current NIC, we can + // 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. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (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) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (UINTN) AttemptConfigOrder[Index] + ); + + GetVariable2 ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptConfigData, + NULL + ); + AsciiStrToUnicodeStrS (AttemptConfigData->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0])); + + if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_DISABLED || + StrCmp (MacString, AttemptMacString)) { + 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); + AttemptConfigData->AutoConfigureSuccess = FALSE; + } + + // + // 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. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (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 + ); + if (AttemptConfigData->AttemptTitleHelpToken == 0) { + return EFI_OUT_OF_RESOURCES; + } + + // + // 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; + UINTN PathLen; + + 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); + + // + // Add a judgement here to support previous versions of IPv4_DEVICE_PATH. + // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask + // do not exist. + // In new version of IPv4_DEVICE_PATH, structure length is 27. + // + + PathLen = DevicePathNodeLength (&DPathNode->Ipv4); + + if (PathLen == IP4_NODE_LEN_NEW_VERSIONS) { + + 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; + + // + // Add a judgement here to support previous versions of IPv6_DEVICE_PATH. + // In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength + // and GatewayIpAddress do not exist. + // In new version of IPv6_DEVICE_PATH, structure length is 60, while in + // old versions, the length is 43. + // + + PathLen = DevicePathNodeLength (&DPathNode->Ipv6); + + if (PathLen == IP6_NODE_LEN_NEW_VERSIONS ) { + + DPathNode->Ipv6.IpAddressOrigin = 0; + DPathNode->Ipv6.PrefixLength = IP6_PREFIX_LENGTH; + ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS)); + } + else if (PathLen == IP6_NODE_LEN_OLD_VERSIONS) { + + // + // StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new + // version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH. + // + *((UINT8 *)(&DPathNode->Ipv6) + IP6_OLD_IPADDRESS_OFFSET) = + (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp); + } + + 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); + Private->ExitBootServiceEvent = NULL; + + if (Private->Session != NULL) { + IScsiSessionAbort (Private->Session); + } +} + +/** + Tests whether a controller handle is being managed by IScsi driver. + + This function tests whether the driver specified by DriverBindingHandle is + currently managing the controller specified by ControllerHandle. This test + is performed by evaluating if the protocol specified by ProtocolGuid is + present on ControllerHandle and is was opened by DriverBindingHandle and Nic + Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER. + If ProtocolGuid is NULL, then ASSERT(). + + @param ControllerHandle A handle for a controller to test. + @param DriverBindingHandle Specifies the driver binding handle for the + driver. + @param ProtocolGuid Specifies the protocol that the driver specified + by DriverBindingHandle opens in its Start() + function. + + @retval EFI_SUCCESS ControllerHandle is managed by the driver + specified by DriverBindingHandle. + @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver + specified by DriverBindingHandle. + +**/ +EFI_STATUS +EFIAPI +IScsiTestManagedDevice ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverBindingHandle, + IN EFI_GUID *ProtocolGuid + ) +{ + EFI_STATUS Status; + VOID *ManagedInterface; + EFI_HANDLE NicControllerHandle; + + ASSERT (ProtocolGuid != NULL); + + NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid); + if (NicControllerHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + (EFI_GUID *) ProtocolGuid, + &ManagedInterface, + DriverBindingHandle, + NicControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + (EFI_GUID *) ProtocolGuid, + DriverBindingHandle, + NicControllerHandle + ); + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} -- cgit 1.2.3-korg