From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c | 3934 ++++++++++++++++++++ 1 file changed, 3934 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c') diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c b/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c new file mode 100644 index 00000000..0c212912 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c @@ -0,0 +1,3934 @@ +/** @file + Helper functions for configuring or getting the parameters relating to iSCSI. + +Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IScsiImpl.h" + +CHAR16 mVendorStorageName[] = L"ISCSI_CONFIG_IFR_NVDATA"; +ISCSI_FORM_CALLBACK_INFO *mCallbackInfo = NULL; + +HII_VENDOR_DEVICE_PATH mIScsiHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + ISCSI_CONFIG_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +/** + Convert the IP address into a dotted string. + + @param[in] Ip The IP address. + @param[in] Ipv6Flag Indicates whether the IP address is version 4 or version 6. + @param[out] Str The formatted IP string. + +**/ +VOID +IScsiIpToStr ( + IN EFI_IP_ADDRESS *Ip, + IN BOOLEAN Ipv6Flag, + OUT CHAR16 *Str + ) +{ + EFI_IPv4_ADDRESS *Ip4; + EFI_IPv6_ADDRESS *Ip6; + UINTN Index; + BOOLEAN Short; + UINTN Number; + CHAR16 FormatString[8]; + + if (!Ipv6Flag) { + Ip4 = &Ip->v4; + + UnicodeSPrint ( + Str, + (UINTN) 2 * IP4_STR_MAX_SIZE, + L"%d.%d.%d.%d", + (UINTN) Ip4->Addr[0], + (UINTN) Ip4->Addr[1], + (UINTN) Ip4->Addr[2], + (UINTN) Ip4->Addr[3] + ); + + return ; + } + + Ip6 = &Ip->v6; + Short = FALSE; + + for (Index = 0; Index < 15; Index = Index + 2) { + if (!Short && + Index % 2 == 0 && + Ip6->Addr[Index] == 0 && + Ip6->Addr[Index + 1] == 0 + ) { + // + // Deal with the case of ::. + // + if (Index == 0) { + *Str = L':'; + *(Str + 1) = L':'; + Str = Str + 2; + } else { + *Str = L':'; + Str = Str + 1; + } + + while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) { + Index = Index + 2; + } + + Short = TRUE; + + if (Index == 16) { + // + // :: is at the end of the address. + // + *Str = L'\0'; + break; + } + } + + ASSERT (Index < 15); + + if (Ip6->Addr[Index] == 0) { + Number = UnicodeSPrint (Str, 2 * IP_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]); + } else { + if (Ip6->Addr[Index + 1] < 0x10) { + CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:")); + } else { + CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:")); + } + + Number = UnicodeSPrint ( + Str, + 2 * IP_STR_MAX_SIZE, + (CONST CHAR16 *) FormatString, + (UINTN) Ip6->Addr[Index], + (UINTN) Ip6->Addr[Index + 1] + ); + } + + Str = Str + Number; + + if (Index + 2 == 16) { + *Str = L'\0'; + if (*(Str - 1) == L':') { + *(Str - 1) = L'\0'; + } + } + } +} + +/** + Check whether the input IP address is valid. + + @param[in] Ip The IP address. + @param[in] IpMode Indicates iSCSI running on IP4 or IP6 stack. + + @retval TRUE The input IP address is valid. + @retval FALSE Otherwise + +**/ +BOOLEAN +IpIsUnicast ( + IN EFI_IP_ADDRESS *Ip, + IN UINT8 IpMode + ) +{ + if (IpMode == IP_MODE_IP4) { + if (IP4_IS_UNSPECIFIED (NTOHL (Ip->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip->Addr[0]))) { + return FALSE; + } + return TRUE; + } else if (IpMode == IP_MODE_IP6) { + return NetIp6IsValidUnicast (&Ip->v6); + } else { + DEBUG ((DEBUG_ERROR, "IpMode %d is invalid when configuring the iSCSI target IP!\n", IpMode)); + return FALSE; + } +} + +/** + Parse IsId in string format and convert it to binary. + + @param[in] String The buffer of the string to be parsed. + @param[in, out] IsId The buffer to store IsId. + + @retval EFI_SUCCESS The operation finished successfully. + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + +**/ +EFI_STATUS +IScsiParseIsIdFromString ( + IN CONST CHAR16 *String, + IN OUT UINT8 *IsId + ) +{ + UINT8 Index; + CHAR16 *IsIdStr; + CHAR16 TempStr[3]; + UINTN NodeVal; + CHAR16 PortString[ISCSI_NAME_IFR_MAX_SIZE]; + EFI_INPUT_KEY Key; + + if ((String == NULL) || (IsId == NULL)) { + return EFI_INVALID_PARAMETER; + } + + IsIdStr = (CHAR16 *) String; + + if (StrLen (IsIdStr) != 6 && StrLen (IsIdStr) != 12) { + UnicodeSPrint ( + PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Error! Only last 3 bytes are configurable, please input 6 hex numbers for last 3 bytes only or 12 hex numbers for full SSID!\n" + ); + + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + PortString, + NULL + ); + + return EFI_INVALID_PARAMETER; + } + + if (StrLen (IsIdStr) == 12) { + IsIdStr += 6; + } + + for (Index = 3; Index < 6; Index++) { + CopyMem (TempStr, IsIdStr, sizeof (TempStr)); + TempStr[2] = L'\0'; + + // + // Convert the string to IsId. StrHexToUintn stops at the first character + // that is not a valid hex character, '\0' here. + // + NodeVal = StrHexToUintn (TempStr); + + IsId[Index] = (UINT8) NodeVal; + + IsIdStr = IsIdStr + 2; + } + + return EFI_SUCCESS; +} + +/** + Convert IsId from binary to string format. + + @param[out] String The buffer to store the converted string. + @param[in] IsId The buffer to store IsId. + + @retval EFI_SUCCESS The string converted successfully. + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + +**/ +EFI_STATUS +IScsiConvertIsIdToString ( + OUT CHAR16 *String, + IN UINT8 *IsId + ) +{ + UINT8 Index; + UINTN Number; + + if ((String == NULL) || (IsId == NULL)) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; Index < 6; Index++) { + if (IsId[Index] <= 0xF) { + Number = UnicodeSPrint ( + String, + 2 * ISID_CONFIGURABLE_STORAGE, + L"0%X", + (UINTN) IsId[Index] + ); + } else { + Number = UnicodeSPrint ( + String, + 2 * ISID_CONFIGURABLE_STORAGE, + L"%X", + (UINTN) IsId[Index] + ); + + } + + String = String + Number; + } + + *String = L'\0'; + + return EFI_SUCCESS; +} + +/** + Get the Offset value specified by the input String. + + @param[in] Configuration A null-terminated Unicode string in + format. + @param[in] String The string is "&OFFSET=". + @param[out] Value The Offset value. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary + structures. + @retval EFI_SUCCESS Value of is outputted in Number + successfully. + +**/ +EFI_STATUS +IScsiGetValue ( + IN CONST EFI_STRING Configuration, + IN CHAR16 *String, + OUT UINTN *Value + ) +{ + CHAR16 *StringPtr; + CHAR16 *TmpPtr; + CHAR16 *Str; + CHAR16 TmpStr[2]; + UINTN Length; + UINTN Len; + UINTN Index; + UINT8 *Buf; + UINT8 DigitUint8; + EFI_STATUS Status; + + // + // Get Value. + // + Buf = NULL; + StringPtr = StrStr (Configuration, String); + ASSERT(StringPtr != NULL); + StringPtr += StrLen (String); + TmpPtr = StringPtr; + + while (*StringPtr != L'\0' && *StringPtr != L'&') { + StringPtr ++; + } + Length = StringPtr - TmpPtr; + Len = Length + 1; + + Str = AllocateZeroPool (Len * sizeof (CHAR16)); + if (Str == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + CopyMem (Str, TmpPtr, Len * sizeof (CHAR16)); + *(Str + Length) = L'\0'; + + Len = (Len + 1) / 2; + Buf = (UINT8 *) AllocateZeroPool (Len); + if (Buf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + ZeroMem (TmpStr, sizeof (TmpStr)); + for (Index = 0; Index < Length; Index ++) { + TmpStr[0] = Str[Length - Index - 1]; + DigitUint8 = (UINT8) StrHexToUint64 (TmpStr); + if ((Index & 1) == 0) { + Buf [Index/2] = DigitUint8; + } else { + Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]); + } + } + + *Value = 0; + CopyMem ( + Value, + Buf, + (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) + ); + + FreePool (Buf); + Status = EFI_SUCCESS; + +Exit: + if (Str != NULL) { + FreePool (Str); + } + + return Status; +} + +/** + Get the attempt config data from global structure by the ConfigIndex. + + @param[in] AttemptConfigIndex The unique index indicates the attempt. + + @return Pointer to the attempt config data. + @retval NULL The attempt configuration data cannot be found. + +**/ +ISCSI_ATTEMPT_CONFIG_NVDATA * +IScsiConfigGetAttemptByConfigIndex ( + IN UINT8 AttemptConfigIndex + ) +{ + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt; + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + if (Attempt->AttemptConfigIndex == AttemptConfigIndex) { + return Attempt; + } + } + + return NULL; +} + + +/** + Get the existing attempt config data from global structure by the NicIndex. + + @param[in] NewAttempt The created new attempt + @param[in] IScsiMode The IScsi Mode of the new attempt, Enabled or + Enabled for MPIO. + + @return Pointer to the existing attempt config data which + has the same NICIndex as the new created attempt. + @retval NULL The attempt with NicIndex does not exist. + +**/ +ISCSI_ATTEMPT_CONFIG_NVDATA * +IScsiConfigGetAttemptByNic ( + IN ISCSI_ATTEMPT_CONFIG_NVDATA *NewAttempt, + IN UINT8 IScsiMode + ) +{ + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt; + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + if (Attempt != NewAttempt && Attempt->NicIndex == NewAttempt->NicIndex && + Attempt->SessionConfigData.Enabled == IScsiMode) { + return Attempt; + } + } + + return NULL; +} + +/** + Extract the Index of the attempt list. + + @param[in] AttemptNameList The Name list of the Attempts. + @param[out] AttemptIndexList The Index list of the Attempts. + @param[in] IsAddAttempts If TRUE, Indicates add one or more attempts. + If FALSE, Indicates delete attempts or change attempt order. + + @retval EFI_SUCCESS The Attempt list is valid. + @retval EFI_INVALID_PARAMETERS The Attempt List is invalid. + +**/ +EFI_STATUS +IScsiGetAttemptIndexList ( + IN CHAR16 *AttemptNameList, + OUT UINT8 *AttemptIndexList, + IN BOOLEAN IsAddAttempts +) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + CHAR16 *AttemptStr; + UINT8 AttemptIndex; + UINTN Len; + UINTN Index; + + Index = 0; + + if ((AttemptNameList == NULL) || (*AttemptNameList == L'\0')) { + return EFI_INVALID_PARAMETER; + } + + AttemptStr = AttemptNameList; + Len = StrLen (L"attempt:"); + + while (*AttemptStr != L'\0') { + AttemptStr = StrStr (AttemptStr, L"attempt:"); + if (AttemptStr == NULL) { + return EFI_INVALID_PARAMETER; + } + AttemptStr += Len; + AttemptIndex = (UINT8)(*AttemptStr - L'0'); + AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (IsAddAttempts) { + if ((AttemptConfigData != NULL) || ((AttemptIndex) > PcdGet8 (PcdMaxIScsiAttemptNumber))) { + return EFI_INVALID_PARAMETER; + } + } else { + if (AttemptConfigData == NULL) { + return EFI_INVALID_PARAMETER; + } + } + + AttemptIndexList[Index] = AttemptIndex; + Index ++; + AttemptStr += 2; + } + return EFI_SUCCESS; +} + +/** + Convert the iSCSI configuration data into the IFR data. + + @param[in] Attempt The iSCSI attempt config data. + @param[in, out] IfrNvData The IFR nv data. + +**/ +VOID +IScsiConvertAttemptConfigDataToIfrNvData ( + IN ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt, + IN OUT ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + ISCSI_SESSION_CONFIG_NVDATA *SessionConfigData; + ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData; + EFI_IP_ADDRESS Ip; + BOOLEAN DnsMode; + + // + // Normal session configuration parameters. + // + SessionConfigData = &Attempt->SessionConfigData; + IfrNvData->Enabled = SessionConfigData->Enabled; + IfrNvData->IpMode = SessionConfigData->IpMode; + DnsMode = SessionConfigData->DnsMode; + + IfrNvData->InitiatorInfoFromDhcp = SessionConfigData->InitiatorInfoFromDhcp; + IfrNvData->TargetInfoFromDhcp = SessionConfigData->TargetInfoFromDhcp; + IfrNvData->TargetPort = SessionConfigData->TargetPort; + + if (IfrNvData->IpMode == IP_MODE_IP4) { + CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->LocalIp); + CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->SubnetMask); + CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->Gateway); + ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp)); + if (SessionConfigData->TargetIp.v4.Addr[0] != '\0') { + CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->TargetIp); + } + + } else if (IfrNvData->IpMode == IP_MODE_IP6) { + ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp)); + if (SessionConfigData->TargetIp.v6.Addr[0] != '\0') { + IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp); + IScsiIpToStr (&Ip, TRUE, IfrNvData->TargetIp); + } + } + + AsciiStrToUnicodeStrS ( + SessionConfigData->TargetName, + IfrNvData->TargetName, + sizeof (IfrNvData->TargetName) / sizeof (IfrNvData->TargetName[0]) + ); + + if (DnsMode) { + AsciiStrToUnicodeStrS ( + SessionConfigData->TargetUrl, + IfrNvData->TargetIp, + sizeof (IfrNvData->TargetIp) / sizeof (IfrNvData->TargetIp[0]) + ); + } + + IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun); + IScsiConvertIsIdToString (IfrNvData->IsId, SessionConfigData->IsId); + + IfrNvData->ConnectRetryCount = SessionConfigData->ConnectRetryCount; + IfrNvData->ConnectTimeout = SessionConfigData->ConnectTimeout; + + // + // Authentication parameters. + // + IfrNvData->AuthenticationType = Attempt->AuthenticationType; + + if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + AuthConfigData = &Attempt->AuthConfigData.CHAP; + IfrNvData->CHAPType = AuthConfigData->CHAPType; + AsciiStrToUnicodeStrS ( + AuthConfigData->CHAPName, + IfrNvData->CHAPName, + sizeof (IfrNvData->CHAPName) / sizeof (IfrNvData->CHAPName[0]) + ); + AsciiStrToUnicodeStrS ( + AuthConfigData->CHAPSecret, + IfrNvData->CHAPSecret, + sizeof (IfrNvData->CHAPSecret) / sizeof (IfrNvData->CHAPSecret[0]) + ); + AsciiStrToUnicodeStrS ( + AuthConfigData->ReverseCHAPName, + IfrNvData->ReverseCHAPName, + sizeof (IfrNvData->ReverseCHAPName) / sizeof (IfrNvData->ReverseCHAPName[0]) + ); + AsciiStrToUnicodeStrS ( + AuthConfigData->ReverseCHAPSecret, + IfrNvData->ReverseCHAPSecret, + sizeof (IfrNvData->ReverseCHAPSecret) / sizeof (IfrNvData->ReverseCHAPSecret[0]) + ); + } + + // + // Other parameters. + // + AsciiStrToUnicodeStrS ( + Attempt->AttemptName, + IfrNvData->AttemptName, + sizeof (IfrNvData->AttemptName) / sizeof (IfrNvData->AttemptName[0]) + ); +} + +/** + Convert the iSCSI configuration data into the IFR data Which will be used + to extract the iSCSI Keyword configuration in format. + + @param[in, out] IfrNvData The IFR nv data. + +**/ +VOID +EFIAPI +IScsiConvertAttemptConfigDataToIfrNvDataByKeyword ( + IN OUT ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt; + ISCSI_SESSION_CONFIG_NVDATA *SessionConfigData; + ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData; + CHAR16 AttemptNameList[ATTEMPT_NAME_LIST_SIZE]; + ISCSI_NIC_INFO *NicInfo; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + EFI_IP_ADDRESS Ip; + UINTN Index; + UINTN StringLen; + + NicInfo = NULL; + ZeroMem (AttemptNameList, sizeof (AttemptNameList)); + + if ((mPrivate != NULL) && (mPrivate->AttemptCount != 0)) { + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + // + // Normal session configuration parameters. + // + SessionConfigData = &Attempt->SessionConfigData; + + ASSERT ((Attempt->AttemptConfigIndex > 0) && (Attempt->AttemptConfigIndex <= FixedPcdGet8 (PcdMaxIScsiAttemptNumber))); + Index = Attempt->AttemptConfigIndex - 1; + + // + // Save the attempt to AttemptNameList as Attempt:1 Attempt:2 + // + AsciiStrToUnicodeStrS ( + Attempt->AttemptName, + AttemptNameList + StrLen (AttemptNameList), + ATTEMPT_NAME_LIST_SIZE - StrLen (AttemptNameList) + ); + + StringLen = StrLen (AttemptNameList); + ASSERT (StringLen > 2); + *(AttemptNameList + StringLen - 2) = L':'; + *(AttemptNameList + StringLen) = L' '; + + AsciiStrToUnicodeStrS ( + Attempt->AttemptName, + IfrNvData->ISCSIAttemptName + ATTEMPT_NAME_SIZE * Index, + ATTEMPT_NAME_LIST_SIZE - ATTEMPT_NAME_SIZE * Index + ); + + IfrNvData->ISCSIBootEnableList[Index] = SessionConfigData->Enabled; + IfrNvData->ISCSIIpAddressTypeList[Index] = SessionConfigData->IpMode; + + IfrNvData->ISCSIInitiatorInfoViaDHCP[Index] = SessionConfigData->InitiatorInfoFromDhcp; + IfrNvData->ISCSITargetInfoViaDHCP[Index] = SessionConfigData->TargetInfoFromDhcp; + IfrNvData->ISCSIConnectRetry[Index] = SessionConfigData->ConnectRetryCount; + IfrNvData->ISCSIConnectTimeout[Index] = SessionConfigData->ConnectTimeout; + IfrNvData->ISCSITargetTcpPort[Index] = SessionConfigData->TargetPort; + + if (SessionConfigData->IpMode == IP_MODE_IP4) { + CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorIpAddress); + CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorNetmask); + CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorGateway); + if (SessionConfigData->TargetIp.v4.Addr[0] != '\0') { + CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS)); + IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSITargetIpAddress); + } + } else if (SessionConfigData->IpMode == IP_MODE_IP6) { + ZeroMem (IfrNvData->Keyword[Index].ISCSITargetIpAddress, sizeof (IfrNvData->TargetIp)); + if (SessionConfigData->TargetIp.v6.Addr[0] != '\0') { + IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp); + IScsiIpToStr (&Ip, TRUE, IfrNvData->Keyword[Index].ISCSITargetIpAddress); + } + } + + AsciiStrToUnicodeStrS ( + SessionConfigData->TargetName, + IfrNvData->Keyword[Index].ISCSITargetName, + ISCSI_NAME_MAX_SIZE + ); + + if (SessionConfigData->DnsMode) { + AsciiStrToUnicodeStrS ( + SessionConfigData->TargetUrl, + IfrNvData->Keyword[Index].ISCSITargetIpAddress, + sizeof (IfrNvData->Keyword[Index].ISCSITargetIpAddress) / sizeof (IfrNvData->Keyword[Index].ISCSITargetIpAddress[0]) + ); + } + + IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->Keyword[Index].ISCSILun); + IScsiConvertIsIdToString (IfrNvData->Keyword[Index].ISCSIIsId, SessionConfigData->IsId); + + IfrNvData->ISCSIAuthenticationMethod[Index] = Attempt->AuthenticationType; + + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + AuthConfigData = &Attempt->AuthConfigData.CHAP; + IfrNvData->ISCSIChapType[Index] = AuthConfigData->CHAPType; + AsciiStrToUnicodeStrS ( + AuthConfigData->CHAPName, + IfrNvData->Keyword[Index].ISCSIChapUsername, + ISCSI_CHAP_NAME_STORAGE + ); + + AsciiStrToUnicodeStrS ( + AuthConfigData->CHAPSecret, + IfrNvData->Keyword[Index].ISCSIChapSecret, + ISCSI_CHAP_SECRET_STORAGE + ); + + AsciiStrToUnicodeStrS ( + AuthConfigData->ReverseCHAPName, + IfrNvData->Keyword[Index].ISCSIReverseChapUsername, + ISCSI_CHAP_NAME_STORAGE + ); + + AsciiStrToUnicodeStrS ( + AuthConfigData->ReverseCHAPSecret, + IfrNvData->Keyword[Index].ISCSIReverseChapSecret, + ISCSI_CHAP_SECRET_STORAGE + ); + } + } + CopyMem(IfrNvData->ISCSIDisplayAttemptList, AttemptNameList, ATTEMPT_NAME_LIST_SIZE); + + ZeroMem (IfrNvData->ISCSIMacAddr, sizeof (IfrNvData->ISCSIMacAddr)); + NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { + NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); + IScsiMacAddrToStr ( + &NicInfo->PermanentAddress, + NicInfo->HwAddressSize, + NicInfo->VlanId, + MacString + ); + CopyMem ( + IfrNvData->ISCSIMacAddr + StrLen (IfrNvData->ISCSIMacAddr), + MacString, + StrLen (MacString) * sizeof (CHAR16) + ); + + *(IfrNvData->ISCSIMacAddr + StrLen (IfrNvData->ISCSIMacAddr)) = L'/'; + } + + StringLen = StrLen (IfrNvData->ISCSIMacAddr); + if (StringLen > 0) { + *(IfrNvData->ISCSIMacAddr + StringLen - 1) = L'\0'; + } + } +} + +/** + Convert the IFR data to iSCSI configuration data. + + @param[in] IfrNvData Point to ISCSI_CONFIG_IFR_NVDATA. + @param[in, out] Attempt The iSCSI attempt config data. + + @retval EFI_INVALID_PARAMETER Any input or configured parameter is invalid. + @retval EFI_NOT_FOUND Cannot find the corresponding variable. + @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_ABORTED The operation is aborted. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConvertIfrNvDataToAttemptConfigData ( + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData, + IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt + ) +{ + EFI_IP_ADDRESS HostIp; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS Gateway; + CHAR16 *MacString; + CHAR16 *AttemptName1; + CHAR16 *AttemptName2; + ISCSI_ATTEMPT_CONFIG_NVDATA *ExistAttempt; + ISCSI_ATTEMPT_CONFIG_NVDATA *SameNicAttempt; + CHAR16 IScsiMode[64]; + CHAR16 IpMode[64]; + ISCSI_NIC_INFO *NicInfo; + EFI_INPUT_KEY Key; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINT8 *AttemptOrderTmp; + UINTN TotalNumber; + EFI_STATUS Status; + + if (IfrNvData == NULL || Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Update those fields which don't have INTERACTIVE attribute. + // + Attempt->SessionConfigData.ConnectRetryCount = IfrNvData->ConnectRetryCount; + Attempt->SessionConfigData.ConnectTimeout = IfrNvData->ConnectTimeout; + Attempt->SessionConfigData.IpMode = IfrNvData->IpMode; + + if (IfrNvData->IpMode < IP_MODE_AUTOCONFIG) { + Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp; + Attempt->SessionConfigData.TargetPort = IfrNvData->TargetPort; + + if (Attempt->SessionConfigData.TargetPort == 0) { + Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT; + } + + Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp; + } + + Attempt->AuthenticationType = IfrNvData->AuthenticationType; + + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->CHAPType; + } + + // + // Only do full parameter validation if iSCSI is enabled on this device. + // + if (IfrNvData->Enabled != ISCSI_DISABLED) { + if (Attempt->SessionConfigData.ConnectTimeout < CONNECT_MIN_TIMEOUT) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Connection Establishing Timeout is less than minimum value 100ms.", + NULL + ); + + return EFI_INVALID_PARAMETER; + } + + // + // Validate the address configuration of the Initiator if DHCP isn't + // deployed. + // + if (!Attempt->SessionConfigData.InitiatorInfoFromDhcp) { + CopyMem (&HostIp.v4, &Attempt->SessionConfigData.LocalIp, sizeof (HostIp.v4)); + CopyMem (&SubnetMask.v4, &Attempt->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4)); + CopyMem (&Gateway.v4, &Attempt->SessionConfigData.Gateway, sizeof (Gateway.v4)); + + if ((Gateway.Addr[0] != 0)) { + if (SubnetMask.Addr[0] == 0) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Gateway address is set but subnet mask is zero.", + NULL + ); + + return EFI_INVALID_PARAMETER; + } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Local IP and Gateway are not in the same subnet.", + NULL + ); + + return EFI_INVALID_PARAMETER; + } + } + } + // + // Validate target configuration if DHCP isn't deployed. + // + if (!Attempt->SessionConfigData.TargetInfoFromDhcp && Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) { + if (!Attempt->SessionConfigData.DnsMode) { + if (!IpIsUnicast (&Attempt->SessionConfigData.TargetIp, IfrNvData->IpMode)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Target IP is invalid!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } else { + if (Attempt->SessionConfigData.TargetUrl[0] == '\0') { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"iSCSI target Url should not be NULL!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + + // + // Validate iSCSI target name configuration again: + // The format of iSCSI target name is already verified in IScsiFormCallback() when + // user input the name; here we only check the case user does not input the name. + // + if (Attempt->SessionConfigData.TargetName[0] == '\0') { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"iSCSI target name is NULL!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + + // + // Validate the authentication info. + // + if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"CHAP Name or CHAP Secret is invalid!", + NULL + ); + + return EFI_INVALID_PARAMETER; + } + + if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) && + ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0')) + ) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Reverse CHAP Name or Reverse CHAP Secret is invalid!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + + // + // Check whether this attempt uses NIC which is already used by existing attempt. + // + SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled); + if (SameNicAttempt != NULL) { + AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16)); + if (AttemptName1 == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16)); + if (AttemptName2 == NULL) { + FreePool (AttemptName1); + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS (Attempt->AttemptName, AttemptName1, ATTEMPT_NAME_SIZE); + AsciiStrToUnicodeStrS (SameNicAttempt->AttemptName, AttemptName2, ATTEMPT_NAME_SIZE); + + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Warning! Attempt \"%s\" uses same NIC as Attempt \"%s\".", + AttemptName1, + AttemptName2 + ); + + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + mPrivate->PortString, + NULL + ); + + FreePool (AttemptName1); + FreePool (AttemptName2); + } + } + + // + // Update the iSCSI Mode data and record it in attempt help info. + // + if (IfrNvData->Enabled == ISCSI_DISABLED) { + UnicodeSPrint (IScsiMode, 64, L"Disabled"); + } else if (IfrNvData->Enabled == ISCSI_ENABLED) { + UnicodeSPrint (IScsiMode, 64, L"Enabled"); + } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) { + UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO"); + } + + if (IfrNvData->IpMode == IP_MODE_IP4) { + UnicodeSPrint (IpMode, 64, L"IP4"); + } else if (IfrNvData->IpMode == IP_MODE_IP6) { + UnicodeSPrint (IpMode, 64, L"IP6"); + } else if (IfrNvData->IpMode == IP_MODE_AUTOCONFIG) { + UnicodeSPrint (IpMode, 64, L"Autoconfigure"); + } + + NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex); + if (NicInfo == NULL) { + return EFI_NOT_FOUND; + } + + MacString = (CHAR16 *) AllocateZeroPool (ISCSI_MAX_MAC_STRING_LEN * sizeof (CHAR16)); + if (MacString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS (Attempt->MacString, MacString, ISCSI_MAX_MAC_STRING_LEN); + + 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 + ); + + Attempt->AttemptTitleHelpToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + Attempt->AttemptTitleHelpToken, + mPrivate->PortString, + NULL + ); + if (Attempt->AttemptTitleHelpToken == 0) { + FreePool (MacString); + return EFI_OUT_OF_RESOURCES; + } + + // + // Check whether this attempt is an existing one. + // + ExistAttempt = IScsiConfigGetAttemptByConfigIndex (Attempt->AttemptConfigIndex); + if (ExistAttempt != NULL) { + ASSERT (ExistAttempt == Attempt); + + if (IfrNvData->Enabled == ISCSI_DISABLED && + Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + + // + // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled". + // + if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { + if (mPrivate->MpioCount < 1) { + return EFI_ABORTED; + } + + if (--mPrivate->MpioCount == 0) { + mPrivate->EnableMpio = FALSE; + } + } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) { + if (mPrivate->SinglePathCount < 1) { + return EFI_ABORTED; + } + mPrivate->SinglePathCount--; + } + + } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO && + Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) { + // + // User updates the Attempt from "Enabled" to "Enabled for MPIO". + // + if (mPrivate->SinglePathCount < 1) { + return EFI_ABORTED; + } + + mPrivate->EnableMpio = TRUE; + mPrivate->MpioCount++; + mPrivate->SinglePathCount--; + + } else if (IfrNvData->Enabled == ISCSI_ENABLED && + Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { + // + // User updates the Attempt from "Enabled for MPIO" to "Enabled". + // + if (mPrivate->MpioCount < 1) { + return EFI_ABORTED; + } + + if (--mPrivate->MpioCount == 0) { + mPrivate->EnableMpio = FALSE; + } + mPrivate->SinglePathCount++; + + } else if (IfrNvData->Enabled != ISCSI_DISABLED && + Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) { + // + // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO". + // + if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) { + mPrivate->EnableMpio = TRUE; + mPrivate->MpioCount++; + + } else if (IfrNvData->Enabled == ISCSI_ENABLED) { + mPrivate->SinglePathCount++; + } + } + + } else if (ExistAttempt == NULL) { + // + // When a new attempt is created, pointer of the attempt is saved to + // mCallbackInfo->Current in IScsiConfigProcessDefault. If input Attempt + // does not match any existing attempt, it should be a new created attempt. + // Save it to system now. + // + + // + // Save current order number for this attempt. + // + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + + TotalNumber = AttemptConfigOrderSize / sizeof (UINT8); + TotalNumber++; + + // + // Append the new created attempt order 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] = Attempt->AttemptConfigIndex; + AttemptConfigOrder = AttemptOrderTmp; + AttemptConfigOrderSize = TotalNumber * sizeof (UINT8); + + Status = gRT->SetVariable ( + L"AttemptOrder", + &gIScsiConfigGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + AttemptConfigOrderSize, + AttemptConfigOrder + ); + FreePool (AttemptConfigOrder); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Insert new created attempt to array. + // + InsertTailList (&mPrivate->AttemptConfigs, &Attempt->Link); + mPrivate->AttemptCount++; + + if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) { + // + // This new Attempt is enabled for MPIO; enable the multipath mode. + // + mPrivate->EnableMpio = TRUE; + mPrivate->MpioCount++; + } else if (IfrNvData->Enabled == ISCSI_ENABLED) { + mPrivate->SinglePathCount++; + } + + IScsiConfigUpdateAttempt (); + } + Attempt->SessionConfigData.Enabled = IfrNvData->Enabled; + + // + // Record the user configuration information in NVR. + // + UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", Attempt->AttemptConfigIndex); + + FreePool (MacString); + + return gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + ISCSI_CONFIG_VAR_ATTR, + sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), + Attempt + ); +} + +/** + Convert the IFR data configured by keyword to iSCSI configuration data. + + @param[in] IfrNvData Point to ISCSI_CONFIG_IFR_NVDATA. + @param[in] OffSet The offset of the variable to the configuration structure. + + @retval EFI_INVALID_PARAMETER Any input or configured parameter is invalid. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConvertlfrNvDataToAttemptConfigDataByKeyword ( + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData, + IN UINTN OffSet + ) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt; + UINT8 AttemptIndex; + UINT8 Index; + UINT8 ChapSecretLen; + UINT8 ReverseChapSecretLen; + CHAR16 *AttemptName1; + CHAR16 *AttemptName2; + ISCSI_ATTEMPT_CONFIG_NVDATA *SameNicAttempt; + CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN]; + CHAR8 IScsiName[ISCSI_NAME_MAX_SIZE]; + CHAR8 IpString[IP_STR_MAX_SIZE]; + EFI_IP_ADDRESS HostIp; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS Gateway; + EFI_INPUT_KEY Key; + UINT64 Lun; + EFI_STATUS Status; + + Attempt = NULL; + ZeroMem (IScsiName, sizeof (IScsiName)); + + if (OffSet < ATTEMPT_BOOTENABLE_VAR_OFFSET) { + return EFI_SUCCESS; + + } else if ((OffSet >= ATTEMPT_BOOTENABLE_VAR_OFFSET) && (OffSet < ATTEMPT_ADDRESS_TYPE_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_BOOTENABLE_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + IfrNvData->Enabled = IfrNvData->ISCSIBootEnableList[AttemptIndex - 1]; + // + // Validate the configuration of attempt. + // + if (IfrNvData->Enabled != ISCSI_DISABLED) { + // + // Check whether this attempt uses NIC which is already used by existing attempt. + // + SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled); + if (SameNicAttempt != NULL) { + AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16)); + if (AttemptName1 == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16)); + if (AttemptName2 == NULL) { + FreePool (AttemptName1); + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS (Attempt->AttemptName, AttemptName1, ATTEMPT_NAME_SIZE); + AsciiStrToUnicodeStrS (SameNicAttempt->AttemptName, AttemptName2, ATTEMPT_NAME_SIZE); + + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Warning! \"%s\" uses same NIC as Attempt \"%s\".", + AttemptName1, + AttemptName2 + ); + + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + mPrivate->PortString, + NULL + ); + + FreePool (AttemptName1); + FreePool (AttemptName2); + } + } + + if (IfrNvData->Enabled == ISCSI_DISABLED && + Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + + // + // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled". + // + if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { + if (mPrivate->MpioCount < 1) { + return EFI_ABORTED; + } + + if (--mPrivate->MpioCount == 0) { + mPrivate->EnableMpio = FALSE; + } + } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) { + if (mPrivate->SinglePathCount < 1) { + return EFI_ABORTED; + } + mPrivate->SinglePathCount--; + } + + } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO && + Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) { + // + // User updates the Attempt from "Enabled" to "Enabled for MPIO". + // + if (mPrivate->SinglePathCount < 1) { + return EFI_ABORTED; + } + + mPrivate->EnableMpio = TRUE; + mPrivate->MpioCount++; + mPrivate->SinglePathCount--; + + } else if (IfrNvData->Enabled == ISCSI_ENABLED && + Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { + // + // User updates the Attempt from "Enabled for MPIO" to "Enabled". + // + if (mPrivate->MpioCount < 1) { + return EFI_ABORTED; + } + + if (--mPrivate->MpioCount == 0) { + mPrivate->EnableMpio = FALSE; + } + mPrivate->SinglePathCount++; + + } else if (IfrNvData->Enabled != ISCSI_DISABLED && + Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) { + // + // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO". + // + if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) { + mPrivate->EnableMpio = TRUE; + mPrivate->MpioCount++; + + } else if (IfrNvData->Enabled == ISCSI_ENABLED) { + mPrivate->SinglePathCount++; + } + } + Attempt->SessionConfigData.Enabled = IfrNvData->Enabled; + + } else if ((OffSet >= ATTEMPT_ADDRESS_TYPE_VAR_OFFSET) && (OffSet < ATTEMPT_CONNECT_RETRY_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_ADDRESS_TYPE_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + Attempt->SessionConfigData.IpMode = IfrNvData->ISCSIIpAddressTypeList[AttemptIndex - 1]; + if (Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) { + Attempt->AutoConfigureMode = 0; + } + + } else if ((OffSet >= ATTEMPT_CONNECT_RETRY_VAR_OFFSET) && (OffSet < ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CONNECT_RETRY_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IfrNvData->ISCSIConnectRetry[AttemptIndex - 1] > CONNECT_MAX_RETRY) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"The minimum value is 0 and the maximum is 16. 0 means no retry.", + NULL + ); + return EFI_INVALID_PARAMETER; + } + Attempt->SessionConfigData.ConnectRetryCount = IfrNvData->ISCSIConnectRetry[AttemptIndex - 1]; + + } else if ((OffSet >= ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET) / 2 + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1] < CONNECT_MIN_TIMEOUT) || + (IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1] > CONNECT_MAX_TIMEOUT)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"The minimum value is 100 milliseconds and the maximum is 20 seconds.", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + Attempt->SessionConfigData.ConnectTimeout = IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1]; + if (Attempt->SessionConfigData.ConnectTimeout == 0) { + Attempt->SessionConfigData.ConnectTimeout = CONNECT_DEFAULT_TIMEOUT; + } + + } else if ((OffSet >= ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->ISCSIInitiatorInfoViaDHCP[AttemptIndex - 1]; + + } else if ((OffSet >= ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (Attempt->SessionConfigData.InitiatorInfoFromDhcp)) { + Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->ISCSITargetInfoViaDHCP[AttemptIndex - 1]; + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Enable DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET) && (OffSet < ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET) / 2 + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) { + Attempt->SessionConfigData.TargetPort = IfrNvData->ISCSITargetTcpPort[AttemptIndex - 1]; + if (Attempt->SessionConfigData.TargetPort == 0) { + Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT; + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Target Via DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET) && (OffSet < ATTEMPT_CHARTYPE_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + Attempt->AuthenticationType = IfrNvData->ISCSIAuthenticationMethod[AttemptIndex - 1]; + + } else if ((OffSet >= ATTEMPT_CHARTYPE_VAR_OFFSET) && (OffSet < ATTEMPT_ISID_VAR_OFFSET)) { + AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CHARTYPE_VAR_OFFSET) + 1); + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->ISCSIChapType[AttemptIndex - 1]; + } + + } else if (OffSet >= ATTEMPT_ISID_VAR_OFFSET) { + Index = (UINT8) ((OffSet - ATTEMPT_ISID_VAR_OFFSET) / sizeof (KEYWORD_STR)); + AttemptIndex = Index + 1; + Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex); + if (Attempt == NULL) { + return EFI_INVALID_PARAMETER; + } + + OffSet = OffSet - Index * sizeof (KEYWORD_STR); + + if ((OffSet >= ATTEMPT_ISID_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET)) { + IScsiParseIsIdFromString (IfrNvData->Keyword[Index].ISCSIIsId, Attempt->SessionConfigData.IsId); + + } else if ((OffSet >= ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) { + // + // Config Local ip + // + Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorIpAddress, &HostIp.v4); + if (EFI_ERROR (Status) || ((Attempt->SessionConfigData.SubnetMask.Addr[0] != 0) && + !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), NTOHL(*(UINT32*)Attempt->SessionConfigData.SubnetMask.Addr)))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid IP address!", + NULL + ); + return EFI_INVALID_PARAMETER; + } else { + CopyMem (&Attempt->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4)); + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Enable DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) { + Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorNetmask, &SubnetMask.v4); + if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Subnet Mask!", + NULL + ); + return EFI_INVALID_PARAMETER; + } else { + CopyMem (&Attempt->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4)); + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Enable DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_NAME_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) { + Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorGateway, &Gateway.v4); + if (EFI_ERROR (Status) || + ((Gateway.Addr[0] != 0) && (Attempt->SessionConfigData.SubnetMask.Addr[0] != 0) && + !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL(*(UINT32*)Attempt->SessionConfigData.SubnetMask.Addr)))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Gateway!", + NULL + ); + return EFI_INVALID_PARAMETER; + } else { + CopyMem (&Attempt->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4)); + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Enable DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_TARGET_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) { + UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetName, IScsiName, ISCSI_NAME_MAX_SIZE); + Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName)); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid iSCSI Name!", + NULL + ); + } else { + AsciiStrCpyS (Attempt->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName); + } + if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + if (Attempt->SessionConfigData.TargetName[0] == L'\0') { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"iSCSI target name is NULL!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Target Via DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET) && (OffSet < ATTEMPT_LUN_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) { + UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetIpAddress, IpString, sizeof (IpString)); + Status = IScsiAsciiStrToIp (IpString, Attempt->SessionConfigData.IpMode, &HostIp); + if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, Attempt->SessionConfigData.IpMode)) { + Attempt->SessionConfigData.DnsMode = TRUE; + ZeroMem (&Attempt->SessionConfigData.TargetIp, sizeof (Attempt->SessionConfigData.TargetIp)); + UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetIpAddress, Attempt->SessionConfigData.TargetUrl, ISCSI_NAME_MAX_SIZE); + } else { + Attempt->SessionConfigData.DnsMode = FALSE; + CopyMem (&Attempt->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp)); + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Target Via DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_LUN_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_USER_NAME_VAR_OFFSET)) { + if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (Attempt->SessionConfigData.TargetInfoFromDhcp == 0)) { + // + // Config LUN. + // + UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSILun, LunString, ISCSI_LUN_STR_MAX_LEN); + Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid LUN string, Examples are: 4752-3A4F-6b7e-2F99, 6734-9-156f-127, 4186-9!", + NULL + ); + } else { + CopyMem (&Attempt->SessionConfigData.BootLun, &Lun, sizeof (Lun)); + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of IpMode or Target Via DHCP!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_CHAR_USER_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_SECRET_VAR_OFFSET)) { + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + UnicodeStrToAsciiStrS ( + IfrNvData->Keyword[Index].ISCSIChapUsername, + Attempt->AuthConfigData.CHAP.CHAPName, + ISCSI_CHAP_NAME_STORAGE + ); + + if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + if (IfrNvData->Keyword[Index].ISCSIChapUsername[0] == L'\0') { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"CHAP Name is invalid!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of AuthenticationType!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_CHAR_SECRET_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET)) { + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + ChapSecretLen = (UINT8)StrLen (IfrNvData->Keyword[Index].ISCSIChapSecret); + UnicodeStrToAsciiStrS ( + IfrNvData->Keyword[Index].ISCSIChapSecret, + Attempt->AuthConfigData.CHAP.CHAPSecret, + ISCSI_CHAP_SECRET_STORAGE + ); + + if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + if ((ChapSecretLen < ISCSI_CHAP_SECRET_MIN_LEN) || (ChapSecretLen > ISCSI_CHAP_SECRET_MAX_LEN)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"The Chap Secret minimum length is 12 bytes and the maximum length is 16 bytes.", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of AuthenticationType!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if ((OffSet >= ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET)) { + if (Attempt->AuthConfigData.CHAP.CHAPType == ISCSI_CHAP_MUTUAL) { + UnicodeStrToAsciiStrS ( + IfrNvData->Keyword[Index].ISCSIReverseChapUsername, + Attempt->AuthConfigData.CHAP.ReverseCHAPName, + ISCSI_CHAP_NAME_STORAGE + ); + if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + if (IfrNvData->Keyword[Index].ISCSIReverseChapUsername[0] == L'\0') { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Reverse CHAP Name is invalid!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of AuthenticationType or Chap Type!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + + } else if (OffSet >= ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET) { + if (Attempt->AuthConfigData.CHAP.CHAPType == ISCSI_CHAP_MUTUAL) { + ReverseChapSecretLen = (UINT8)StrLen (IfrNvData->Keyword[Index].ISCSIReverseChapSecret); + UnicodeStrToAsciiStrS ( + IfrNvData->Keyword[Index].ISCSIReverseChapSecret, + Attempt->AuthConfigData.CHAP.ReverseCHAPSecret, + ISCSI_CHAP_SECRET_STORAGE + ); + + if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) { + if ((ReverseChapSecretLen < ISCSI_CHAP_SECRET_MIN_LEN) || (ReverseChapSecretLen > ISCSI_CHAP_SECRET_MAX_LEN)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"The Reverse CHAP Secret minimum length is 12 bytes and the maximum length is 16 bytes.", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Configuration, Check value of AuthenticationType or Chap Type!", + NULL + ); + return EFI_INVALID_PARAMETER; + } + } + } + + + + // + // Record the user configuration information in NVR. + // + ASSERT (Attempt != NULL); + UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", Attempt->AttemptConfigIndex); + return gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + ISCSI_CONFIG_VAR_ATTR, + sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), + Attempt + ); + +} + +/** + Create Hii Extend Label OpCode as the start opcode and end opcode. It is + a help function. + + @param[in] StartLabelNumber The number of start label. + @param[out] StartOpCodeHandle Points to the start opcode handle. + @param[out] StartLabel Points to the created start opcode. + @param[out] EndOpCodeHandle Points to the end opcode handle. + @param[out] EndLabel Points to the created end opcode. + + @retval EFI_OUT_OF_RESOURCES Do not have sufficient resource to finish this + operation. + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiCreateOpCode ( + IN UINT16 StartLabelNumber, + OUT VOID **StartOpCodeHandle, + OUT EFI_IFR_GUID_LABEL **StartLabel, + OUT VOID **EndOpCodeHandle, + OUT EFI_IFR_GUID_LABEL **EndLabel + ) +{ + EFI_STATUS Status; + EFI_IFR_GUID_LABEL *InternalStartLabel; + EFI_IFR_GUID_LABEL *InternalEndLabel; + + if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) { + return EFI_INVALID_PARAMETER; + } + + *StartOpCodeHandle = NULL; + *EndOpCodeHandle = NULL; + Status = EFI_OUT_OF_RESOURCES; + + // + // Initialize the container for dynamic opcodes. + // + *StartOpCodeHandle = HiiAllocateOpCodeHandle (); + if (*StartOpCodeHandle == NULL) { + return Status; + } + + *EndOpCodeHandle = HiiAllocateOpCodeHandle (); + if (*EndOpCodeHandle == NULL) { + goto Exit; + } + + // + // Create Hii Extend Label OpCode as the start opcode. + // + InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + *StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + if (InternalStartLabel == NULL) { + goto Exit; + } + + InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + InternalStartLabel->Number = StartLabelNumber; + + // + // Create Hii Extend Label OpCode as the end opcode. + // + InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + *EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + if (InternalEndLabel == NULL) { + goto Exit; + } + + InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + InternalEndLabel->Number = LABEL_END; + + *StartLabel = InternalStartLabel; + *EndLabel = InternalEndLabel; + + return EFI_SUCCESS; + +Exit: + + if (*StartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (*StartOpCodeHandle); + } + + if (*EndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (*EndOpCodeHandle); + } + return Status; +} + +/** + Update the MAIN form to display the configured attempts. + +**/ +VOID +IScsiConfigUpdateAttempt ( + VOID + ) +{ + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + VOID *StartOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *EndLabel; + EFI_STATUS Status; + + Status = IScsiCreateOpCode ( + ATTEMPT_ENTRY_LABEL, + &StartOpCodeHandle, + &StartLabel, + &EndOpCodeHandle, + &EndLabel + ); + if (EFI_ERROR (Status)) { + return ; + } + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + if (AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) { + // + // Update Attempt Help Info. + // + UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", (UINTN) AttemptConfigData->AttemptConfigIndex); + AttemptConfigData->AttemptTitleToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + mPrivate->PortString, + NULL + ); + if (AttemptConfigData->AttemptTitleToken == 0) { + return ; + } + + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + FORMID_ATTEMPT_FORM, // Form ID + AttemptConfigData->AttemptTitleToken, // Prompt text + AttemptConfigData->AttemptTitleHelpToken, // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + (UINT16) (KEY_ATTEMPT_ENTRY_BASE + AttemptConfigData->AttemptConfigIndex) // Question ID + ); + } + } + + HiiUpdateForm ( + mCallbackInfo->RegisteredHandle, // HII handle + &gIScsiConfigGuid, // Formset GUID + FORMID_MAIN_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + +/** + Callback function when user presses "Add an Attempt". + + @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this + operation. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConfigAddAttempt ( + VOID + ) +{ + LIST_ENTRY *Entry; + ISCSI_NIC_INFO *NicInfo; + EFI_STRING_ID PortTitleToken; + EFI_STRING_ID PortTitleHelpToken; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + EFI_STATUS Status; + VOID *StartOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *EndLabel; + + Status = IScsiCreateOpCode ( + MAC_ENTRY_LABEL, + &StartOpCodeHandle, + &StartLabel, + &EndOpCodeHandle, + &EndLabel + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Ask user to select a MAC for this attempt. + // + NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { + NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); + IScsiMacAddrToStr ( + &NicInfo->PermanentAddress, + NicInfo->HwAddressSize, + NicInfo->VlanId, + MacString + ); + + UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"MAC %s", MacString); + PortTitleToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + mPrivate->PortString, + NULL + ); + if (PortTitleToken == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"PFA: Bus %d | Dev %d | Func %d", + NicInfo->BusNumber, + NicInfo->DeviceNumber, + NicInfo->FunctionNumber + ); + PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, mPrivate->PortString, NULL); + if (PortTitleHelpToken == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + FORMID_ATTEMPT_FORM, + PortTitleToken, + PortTitleHelpToken, + EFI_IFR_FLAG_CALLBACK, // Question flag + (UINT16) (KEY_MAC_ENTRY_BASE + NicInfo->NicIndex) + ); + } + + Status = HiiUpdateForm ( + mCallbackInfo->RegisteredHandle, // HII handle + &gIScsiConfigGuid, // Formset GUID + FORMID_MAC_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + +Exit: + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return Status; +} + +/** + Add the attempts by keyword 'iSCSIAddAttempts', you can use this keyword with + value 'attempt:1 attempt:2' etc to add one or more attempts once. This is different + with IScsiConfigAddAttempt function which is used to add attempt by UI configuration. + + @param[in] AttemptList The new attempt List will be added. + + @retval EFI_SUCCESS The operation to add attempt list successfully. + @retval EFI_INVALID_PARAMETER Any parameter is invalid. + @retval EFI_NOT_FOUND Cannot find the corresponding variable. + @retval EFI_OUT_OF_RESOURCES Fail to finish the operation due to lack of + resources. + +**/ +EFI_STATUS +IScsiConfigAddAttemptsByKeywords ( + IN UINT8 *AttemptList + ) +{ + UINT8 Index; + UINT8 Number; + UINTN TotalNumber; + UINT8 Nic; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINT8 *AttemptConfigOrderTmp; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + ISCSI_NIC_INFO *NicInfo; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR16 IScsiMode[64]; + CHAR16 IpMode[64]; + EFI_STATUS Status; + + Nic = mPrivate->CurrentNic; + NicInfo = IScsiGetNicInfoByIndex (Nic); + if (NicInfo == NULL) { + return EFI_NOT_FOUND; + } + + // + // The MAC info will be recorded in Config Data. + // + IScsiMacAddrToStr ( + &NicInfo->PermanentAddress, + NicInfo->HwAddressSize, + NicInfo->VlanId, + MacString + ); + + for (Index = 0; Index < PcdGet8 (PcdMaxIScsiAttemptNumber); Index++) { + if (AttemptList[Index] == 0) { + continue; + } + + // + // Add the attempt. + // + Number = AttemptList[Index]; + + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + Number + ); + + GetVariable2 ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptConfigData, + NULL + ); + if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) { + return EFI_INVALID_PARAMETER; + } + + AttemptConfigData->Actived = ISCSI_ACTIVE_ENABLED; + AttemptConfigData->NicIndex = NicInfo->NicIndex; + UnicodeStrToAsciiStrS (MacString, AttemptConfigData->MacString, ISCSI_MAX_MAC_STRING_LEN); + + // + // Generate OUI-format ISID based on MAC address. + // + CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6); + AttemptConfigData->SessionConfigData.IsId[0] = + (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F); + + // + // Configure the iSCSI Mode and IpMode to default. + // Add Attempt Help Info. + // + UnicodeSPrint (IScsiMode, 64, L"Disabled"); + UnicodeSPrint (IpMode, 64, L"IP4"); + 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; + } + + // + // Get current Attempt order and number. + // + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + TotalNumber = AttemptConfigOrderSize / sizeof (UINT8); + TotalNumber++; + + // + // Append the new created attempt order to the end. + // + AttemptConfigOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8)); + if (AttemptConfigOrderTmp == NULL) { + if (AttemptConfigOrder != NULL) { + FreePool (AttemptConfigOrder); + } + return EFI_OUT_OF_RESOURCES; + } + if (AttemptConfigOrder != NULL) { + CopyMem (AttemptConfigOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize); + FreePool (AttemptConfigOrder); + } + + AttemptConfigOrderTmp[TotalNumber - 1] = Number; + AttemptConfigOrder = AttemptConfigOrderTmp; + AttemptConfigOrderSize = TotalNumber * sizeof (UINT8); + + Status = gRT->SetVariable ( + L"AttemptOrder", + &gIScsiConfigGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + AttemptConfigOrderSize, + AttemptConfigOrder + ); + FreePool (AttemptConfigOrder); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Record the attempt in global link list. + // + InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link); + mPrivate->AttemptCount++; + UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", AttemptConfigData->AttemptConfigIndex); + gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + ISCSI_CONFIG_VAR_ATTR, + sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), + AttemptConfigData + ); + + } + + return EFI_SUCCESS; +} + +/** + Callback function when user presses "Commit Changes and Exit" in Delete Attempts or Delete Attempts by Keyword. + + @param[in] IfrNvData The IFR NV data. + + @retval EFI_NOT_FOUND Cannot find the corresponding variable. + @retval EFI_SUCCESS The operation is completed successfully. + @retval EFI_ABORTED This operation is aborted cause of error + configuration. + @retval EFI_OUT_OF_RESOURCES Fail to finish the operation due to lack of + resources. + +**/ +EFI_STATUS +IScsiConfigDeleteAttempts ( + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN NewIndex; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINT8 *AttemptNewOrder; + UINT8 AttemptConfigIndex; + UINT32 Attribute; + UINTN Total; + UINTN NewTotal; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + ISCSI_SESSION_CONFIG_NVDATA *ConfigData; + + Index = 0; + + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if ((AttemptConfigOrder == NULL) || (AttemptConfigOrderSize == 0)) { + return EFI_NOT_FOUND; + } + + AttemptNewOrder = AllocateZeroPool (AttemptConfigOrderSize); + if (AttemptNewOrder == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Total = AttemptConfigOrderSize / sizeof (UINT8); + NewTotal = Total; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) { + if (IfrNvData->DeleteAttemptList[Index] == 0) { + Index++; + continue; + } + + // + // Delete the attempt. + // + + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + + // + // Remove this attempt from UI configured attempt list. + // + RemoveEntryList (&AttemptConfigData->Link); + mPrivate->AttemptCount--; + + if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { + if (mPrivate->MpioCount < 1) { + Status = EFI_ABORTED; + goto Error; + } + + // + // No more attempt is enabled for MPIO. Transit the iSCSI mode to single path. + // + if (--mPrivate->MpioCount == 0) { + mPrivate->EnableMpio = FALSE; + } + } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) { + if (mPrivate->SinglePathCount < 1) { + Status = EFI_ABORTED; + goto Error; + } + + mPrivate->SinglePathCount--; + } + + AttemptConfigIndex = AttemptConfigData->AttemptConfigIndex; + FreePool (AttemptConfigData); + + // + // Create a 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 = AttemptConfigIndex; + + // + // Set the attempt name to default. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (UINTN) AttemptConfigData->AttemptConfigIndex + ); + UnicodeStrToAsciiStrS (mPrivate->PortString, AttemptConfigData->AttemptName, ATTEMPT_NAME_SIZE); + gRT->SetVariable ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + ISCSI_CONFIG_VAR_ATTR, + sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), + AttemptConfigData + ); + + // + // Mark the attempt order in NVR to be deleted - 0. + // + for (NewIndex = 0; NewIndex < Total; NewIndex++) { + if (AttemptConfigOrder[NewIndex] == AttemptConfigData->AttemptConfigIndex) { + AttemptConfigOrder[NewIndex] = 0; + break; + } + } + + NewTotal--; + if (mCallbackInfo->Current == AttemptConfigData) { + mCallbackInfo->Current = NULL; + } + FreePool (AttemptConfigData); + + // + // Check next Attempt. + // + Index++; + } + + // + // Construct AttemptNewOrder. + // + for (Index = 0, NewIndex = 0; Index < Total; Index++) { + if (AttemptConfigOrder[Index] != 0) { + AttemptNewOrder[NewIndex] = AttemptConfigOrder[Index]; + NewIndex++; + } + } + + Attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE; + + // + // Update AttemptOrder in NVR. + // + Status = gRT->SetVariable ( + L"AttemptOrder", + &gIScsiConfigGuid, + Attribute, + NewTotal * sizeof (UINT8), + AttemptNewOrder + ); + +Error: + if (AttemptConfigOrder != NULL) { + FreePool (AttemptConfigOrder); + } + + if (AttemptNewOrder != NULL) { + FreePool (AttemptNewOrder); + } + + return Status; +} + + +/** + Callback function when user presses "Delete Attempts". + + @param[in] IfrNvData The IFR nv data. + + @retval EFI_INVALID_PARAMETER Any parameter is invalid. + @retval EFI_BUFFER_TOO_SMALL The buffer in UpdateData is too small. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConfigDisplayDeleteAttempts ( + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + UINT8 Index; + VOID *StartOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *EndLabel; + EFI_STATUS Status; + + Status = IScsiCreateOpCode ( + DELETE_ENTRY_LABEL, + &StartOpCodeHandle, + &StartLabel, + &EndOpCodeHandle, + &EndLabel + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if (AttemptConfigOrder != NULL) { + // + // Create the check box opcode to be deleted. + // + Index = 0; + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + IfrNvData->DeleteAttemptList[Index] = 0x00; + + HiiCreateCheckBoxOpCode( + StartOpCodeHandle, + (EFI_QUESTION_ID) (ATTEMPT_DEL_QUESTION_ID + Index), + CONFIGURATION_VARSTORE_ID, + (UINT16) (ATTEMPT_DEL_VAR_OFFSET + Index), + AttemptConfigData->AttemptTitleToken, + AttemptConfigData->AttemptTitleHelpToken, + 0, + 0, + NULL + ); + + Index++; + + if (Index == ISCSI_MAX_ATTEMPTS_NUM) { + break; + } + } + + FreePool (AttemptConfigOrder); + } + + Status = HiiUpdateForm ( + mCallbackInfo->RegisteredHandle, // HII handle + &gIScsiConfigGuid, // Formset GUID + FORMID_DELETE_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return Status; +} + + +/** + Callback function when user presses "Change Attempt Order". + + @retval EFI_INVALID_PARAMETER Any parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this + operation. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConfigDisplayOrderAttempts ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 Index; + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + VOID *StartOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *EndLabel; + VOID *OptionsOpCodeHandle; + + Status = IScsiCreateOpCode ( + ORDER_ENTRY_LABEL, + &StartOpCodeHandle, + &StartLabel, + &EndOpCodeHandle, + &EndLabel + ); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (StartOpCodeHandle != NULL); + + OptionsOpCodeHandle = NULL; + + // + // If no attempt to be ordered, update the original form and exit. + // + if (mPrivate->AttemptCount == 0) { + goto Exit; + } + + // + // Create Option OpCode. + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + if (OptionsOpCodeHandle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Index = 0; + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + AttemptConfigData->AttemptTitleToken, + 0, + EFI_IFR_NUMERIC_SIZE_1, + AttemptConfigData->AttemptConfigIndex + ); + Index++; + } + + ASSERT (Index == mPrivate->AttemptCount); + + HiiCreateOrderedListOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + DYNAMIC_ORDERED_LIST_QUESTION_ID, // Question ID + CONFIGURATION_VARSTORE_ID, // VarStore ID + DYNAMIC_ORDERED_LIST_VAR_OFFSET, // Offset in Buffer Storage + STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY), // Question prompt text + STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY), // Question help text + 0, // Question flag + EFI_IFR_UNIQUE_SET, // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question value + ISCSI_MAX_ATTEMPTS_NUM, // Maximum container + OptionsOpCodeHandle, // Option Opcode list + NULL // Default Opcode is NULL + ); + +Exit: + Status = HiiUpdateForm ( + mCallbackInfo->RegisteredHandle, // HII handle + &gIScsiConfigGuid, // Formset GUID + FORMID_ORDER_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + +Error: + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + if (OptionsOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + } + + return Status; +} + +/** + Callback function when user presses "Commit Changes and Exit" in Change Attempt Order or Change Attempt Order by Keyword. + + @param[in] IfrNvData The IFR nv data. + + @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this + operation. + @retval EFI_NOT_FOUND Cannot find the corresponding variable. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConfigOrderAttempts ( + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN Indexj; + UINT8 AttemptConfigIndex; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + UINT8 *AttemptConfigOrder; + UINT8 *AttemptConfigOrderTmp; + UINTN AttemptConfigOrderSize; + + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"AttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + if (AttemptConfigOrder == NULL) { + return EFI_NOT_FOUND; + } + + AttemptConfigOrderTmp = AllocateZeroPool (AttemptConfigOrderSize); + if (AttemptConfigOrderTmp == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + for (Index = 0; Index < ISCSI_MAX_ATTEMPTS_NUM; Index++) { + // + // The real content ends with 0. + // + if (IfrNvData->DynamicOrderedList[Index] == 0) { + break; + } + + AttemptConfigIndex = IfrNvData->DynamicOrderedList[Index]; + AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigIndex); + if (AttemptConfigData == NULL) { + Status = EFI_NOT_FOUND; + goto Exit; + } + + // + // Reorder the Attempt List. + // + RemoveEntryList (&AttemptConfigData->Link); + InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link); + + AttemptConfigOrderTmp[Index] = AttemptConfigIndex; + + // + // Mark it to be deleted - 0. + // + for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) { + if (AttemptConfigOrder[Indexj] == AttemptConfigIndex) { + AttemptConfigOrder[Indexj] = 0; + break; + } + } + } + + // + // Adjust the attempt order in NVR. + // + for (; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { + for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) { + if (AttemptConfigOrder[Indexj] != 0) { + AttemptConfigOrderTmp[Index] = AttemptConfigOrder[Indexj]; + AttemptConfigOrder[Indexj] = 0; + continue; + } + } + } + + Status = gRT->SetVariable ( + L"AttemptOrder", + &gIScsiConfigGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + AttemptConfigOrderSize, + AttemptConfigOrderTmp + ); + +Exit: + if (AttemptConfigOrderTmp != NULL) { + FreePool (AttemptConfigOrderTmp); + } + + FreePool (AttemptConfigOrder); + return Status; +} + + +/** + Callback function when a user presses "Attempt *" or when a user selects a NIC to + create the new attempt. + + @param[in] KeyValue A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] IfrNvData The IFR nv data. + + @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this + operation. + @retval EFI_NOT_FOUND Cannot find the corresponding variable. + @retval EFI_UNSUPPORTED Can not create more attempts. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +IScsiConfigProcessDefault ( + IN EFI_QUESTION_ID KeyValue, + IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData + ) +{ + BOOLEAN NewAttempt; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + UINT8 CurrentAttemptConfigIndex; + ISCSI_NIC_INFO *NicInfo; + UINT8 NicIndex; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + UINT8 *AttemptConfigOrder; + UINTN AttemptConfigOrderSize; + UINTN Index; + EFI_INPUT_KEY Key; + + AttemptConfigData = NULL; + // + // Is User creating a new attempt? + // + NewAttempt = FALSE; + + if ((KeyValue >= KEY_MAC_ENTRY_BASE) && + (KeyValue <= (UINT16) (mPrivate->MaxNic + KEY_MAC_ENTRY_BASE))) { + // + // User has pressed "Add an Attempt" and then selects a NIC. + // + NewAttempt = TRUE; + } else if ((KeyValue >= KEY_ATTEMPT_ENTRY_BASE) && + (KeyValue < (ISCSI_MAX_ATTEMPTS_NUM + KEY_ATTEMPT_ENTRY_BASE))) { + + // + // User has pressed "Attempt *". + // + NewAttempt = FALSE; + } else { + // + // Don't process anything. + // + return EFI_SUCCESS; + } + + if (NewAttempt) { + // + // Determine which NIC user has selected for the new created attempt. + // + NicIndex = (UINT8) (KeyValue - KEY_MAC_ENTRY_BASE); + NicInfo = IScsiGetNicInfoByIndex (NicIndex); + if (NicInfo == NULL) { + return EFI_NOT_FOUND; + } + + // + // Create an attempt following the initialized attempt order. + // + AttemptConfigOrder = IScsiGetVariableAndSize ( + L"InitialAttemptOrder", + &gIScsiConfigGuid, + &AttemptConfigOrderSize + ); + + if (AttemptConfigOrder == NULL) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"Attempt %d", + (UINTN) AttemptConfigOrder[Index] + ); + GetVariable2 ( + mPrivate->PortString, + &gEfiIScsiInitiatorNameProtocolGuid, + (VOID**)&AttemptConfigData, + NULL + ); + if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) { + continue; + } + + break; + } + + if (Index > PcdGet8 (PcdMaxIScsiAttemptNumber)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Can not create more attempts, Please configure the PcdMaxIScsiAttemptNumber if needed!", + NULL + ); + return EFI_UNSUPPORTED; + } + + if (AttemptConfigOrder != NULL) { + FreePool (AttemptConfigOrder); + } + + // + // Record the MAC info in Config Data. + // + IScsiMacAddrToStr ( + &NicInfo->PermanentAddress, + NicInfo->HwAddressSize, + NicInfo->VlanId, + MacString + ); + + ASSERT (AttemptConfigData != NULL); + UnicodeStrToAsciiStrS (MacString, AttemptConfigData->MacString, sizeof (AttemptConfigData->MacString)); + AttemptConfigData->NicIndex = NicIndex; + AttemptConfigData->Actived = ISCSI_ACTIVE_ENABLED; + + // + // Generate OUI-format ISID based on MAC address. + // + CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6); + AttemptConfigData->SessionConfigData.IsId[0] = + (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F); + + // + // Add the help info for the new attempt. + // + UnicodeSPrint ( + mPrivate->PortString, + (UINTN) ISCSI_NAME_IFR_MAX_SIZE, + L"MAC: %s, PFA: Bus %d | Dev %d | Func %d", + MacString, + NicInfo->BusNumber, + NicInfo->DeviceNumber, + NicInfo->FunctionNumber + ); + + AttemptConfigData->AttemptTitleHelpToken = HiiSetString ( + mCallbackInfo->RegisteredHandle, + 0, + mPrivate->PortString, + NULL + ); + if (AttemptConfigData->AttemptTitleHelpToken == 0) { + FreePool (AttemptConfigData); + return EFI_OUT_OF_RESOURCES; + } + + } else { + // + // Determine which Attempt user has selected to configure. + // Get the attempt configuration data. + // + CurrentAttemptConfigIndex = (UINT8) (KeyValue - KEY_ATTEMPT_ENTRY_BASE); + + AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (CurrentAttemptConfigIndex); + if (AttemptConfigData == NULL) { + DEBUG ((DEBUG_ERROR, "Corresponding configuration data can not be retrieved!\n")); + return EFI_NOT_FOUND; + } + } + + // + // Clear the old IFR data to avoid sharing it with other attempts. + // + if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + ZeroMem (IfrNvData->CHAPName, sizeof (IfrNvData->CHAPName)); + ZeroMem (IfrNvData->CHAPSecret, sizeof (IfrNvData->CHAPSecret)); + ZeroMem (IfrNvData->ReverseCHAPName, sizeof (IfrNvData->ReverseCHAPName)); + ZeroMem (IfrNvData->ReverseCHAPSecret, sizeof (IfrNvData->ReverseCHAPSecret)); + } + + IScsiConvertAttemptConfigDataToIfrNvData (AttemptConfigData, IfrNvData); + + // + // Update current attempt to be a new created attempt or an existing attempt. + // + mCallbackInfo->Current = AttemptConfigData; + + return EFI_SUCCESS; +} + + +/** + + This function allows the caller to request the current + configuration for one or more named elements. The resulting + string is in format. Also, any and all alternative + configuration strings shall be appended to the end of the + current configuration string. If they are, they must appear + after the current configuration. They must contain the same + routing (GUID, NAME, PATH) as the current configuration string. + They must have an additional description indicating the type of + alternative configuration the string represents, + "ALTCFG=". That (when + converted from Hex UNICODE to binary) is a reference to a + string in the associated string pack. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + + @param[in] Request A null-terminated Unicode string in + format. Note that this + includes the routing information as well as + the configurable name / value pairs. It is + invalid for this string to be in + format. + + @param[out] Progress On return, points to a character in the + Request string. Points to the string's null + terminator if request was successful. Points + to the most recent "&" before the first + failing name / value pair (or the beginning + of the string if the failure is in the first + name / value pair) if the request was not successful. + + @param[out] Results A null-terminated Unicode string in + format which has all values + filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results string is filled with the + values corresponding to all requested + names. + + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the + parts of the results that must be + stored awaiting possible future + protocols. + + @retval EFI_INVALID_PARAMETER For example, passing in a NULL + for the Request parameter + would result in this type of + error. In this case, the + Progress parameter would be + set to NULL. + + @retval EFI_NOT_FOUND Routing data doesn't match any + known driver. Progress set to the + first character in the routing header. + Note: There is no requirement that the + driver validate the routing data. It + must skip the in order to + process the names. + + @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set + to most recent "&" before the + error or the beginning of the + string. + + @retval EFI_INVALID_PARAMETER Unknown name. Progress points + to the & before the name in + question. + +**/ +EFI_STATUS +EFIAPI +IScsiFormExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + EFI_STATUS Status; + CHAR8 *InitiatorName; + UINTN BufferSize; + ISCSI_CONFIG_IFR_NVDATA *IfrNvData; + ISCSI_FORM_CALLBACK_INFO *Private; + EFI_STRING ConfigRequestHdr; + EFI_STRING ConfigRequest; + BOOLEAN AllocatedRequest; + UINTN Size; + + if (This == NULL || Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Request; + if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gIScsiConfigGuid, mVendorStorageName)) { + return EFI_NOT_FOUND; + } + + ConfigRequestHdr = NULL; + ConfigRequest = NULL; + AllocatedRequest = FALSE; + Size = 0; + + Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This); + IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA)); + if (IfrNvData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + + if (Private->Current!= NULL) { + IScsiConvertAttemptConfigDataToIfrNvData (Private->Current, IfrNvData); + } + + // + // Extract all AttemptConfigData to Keyword storage of IfrNvData. + // + IScsiConvertAttemptConfigDataToIfrNvDataByKeyword (IfrNvData); + + BufferSize = ISCSI_NAME_MAX_SIZE; + InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize); + if (InitiatorName == NULL) { + FreePool (IfrNvData); + return EFI_OUT_OF_RESOURCES; + } + + Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName); + if (EFI_ERROR (Status)) { + IfrNvData->InitiatorName[0] = L'\0'; + } else { + AsciiStrToUnicodeStrS ( + InitiatorName, + IfrNvData->InitiatorName, + sizeof (IfrNvData->InitiatorName) / sizeof (IfrNvData->InitiatorName[0]) + ); + } + + // + // Convert buffer data to by helper function BlockToConfig(). + // + BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA); + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request has no request element, construct full request string. + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + ConfigRequestHdr = HiiConstructConfigHdr (&gIScsiConfigGuid, mVendorStorageName, Private->DriverHandle); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + if (ConfigRequest == NULL) { + FreePool (IfrNvData); + FreePool (InitiatorName); + return EFI_OUT_OF_RESOURCES; + } + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); + FreePool (ConfigRequestHdr); + } + + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + (UINT8 *) IfrNvData, + BufferSize, + Results, + Progress + ); + FreePool (IfrNvData); + FreePool (InitiatorName); + + // + // Free the allocated config request string. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + ConfigRequest = NULL; + } + // + // Set Progress string to the original request string. + // + if (Request == NULL) { + *Progress = NULL; + } else if (StrStr (Request, L"OFFSET") == NULL) { + *Progress = Request + StrLen (Request); + } + + return Status; +} + + +/** + + This function applies changes in a driver's configuration. + Input is a Configuration, which has the routing data for this + driver followed by name / value configuration pairs. The driver + must apply those pairs to its configurable storage. If the + driver's configuration is stored in a linear block of data + and the driver's name / value pairs are in + format, it may use the ConfigToBlock helper function (above) to + simplify the job. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + + @param[in] Configuration A null-terminated Unicode string in + format. + + @param[out] Progress A pointer to a string filled in with the + offset of the most recent '&' before the + first failing name / value pair (or the + beginning of the string if the failure + is in the first name / value pair) or + the terminating NULL if all was + successful. + + @retval EFI_SUCCESS The results have been distributed or are + awaiting distribution. + + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the + parts of the results that must be + stored awaiting possible future + protocols. + + @retval EFI_INVALID_PARAMETERS Passing in a NULL for the + Results parameter would result + in this type of error. + + @retval EFI_NOT_FOUND Target for the specified routing data + was not found. + +**/ +EFI_STATUS +EFIAPI +IScsiFormRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + EFI_STATUS Status; + ISCSI_CONFIG_IFR_NVDATA *IfrNvData; + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + ISCSI_NIC_INFO *NicInfo; + EFI_INPUT_KEY Key; + CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; + CHAR8 *InitiatorName; + UINT8 *AttemptList; + UINTN BufferSize; + UINTN OffSet; + UINTN Index; + UINTN Index2; + + Index = 0; + Index2 = 0; + NicInfo = NULL; + AttemptList = NULL; + Status = EFI_SUCCESS; + + if (This == NULL || Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check routing data in . + // Note: if only one Storage is used, then this checking could be skipped. + // + if (!HiiIsConfigHdrMatch (Configuration, &gIScsiConfigGuid, mVendorStorageName)) { + *Progress = Configuration; + return EFI_NOT_FOUND; + } + + IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA)); + if (IfrNvData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BufferSize = ISCSI_NAME_MAX_SIZE; + InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize); + if (InitiatorName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Convert to buffer data by helper function ConfigToBlock(). + // + BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA); + Status = gHiiConfigRouting->ConfigToBlock ( + gHiiConfigRouting, + Configuration, + (UINT8 *) IfrNvData, + &BufferSize, + Progress + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + if (IfrNvData->InitiatorName[0] != L'\0') { + UnicodeStrToAsciiStrS (IfrNvData->InitiatorName, InitiatorName, ISCSI_NAME_MAX_SIZE); + BufferSize = AsciiStrSize (InitiatorName); + + Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, InitiatorName); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid iSCSI Name!", + NULL + ); + goto Exit; + } + } else { + Status = IScsiGetValue (Configuration, L"&OFFSET=", &OffSet); + if (EFI_ERROR (Status)) { + goto Exit; + } + + if (OffSet >= ATTEMPT_MAC_ADDR_VAR_OFFSET) { + Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: please configure iSCSI initiator name first!", + NULL + ); + goto Exit; + } + } else { + goto Exit; + } + + if (IfrNvData->ISCSIAddAttemptList[0] != L'\0') { + Status =IScsiGetAttemptIndexList (IfrNvData->ISCSIAddAttemptList, IfrNvData->AddAttemptList, TRUE); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: The add attempt list is invalid", + NULL + ); + goto Exit; + } + + Status = IScsiConfigAddAttemptsByKeywords (IfrNvData->AddAttemptList); + if (EFI_ERROR (Status)) { + goto Exit; + } + + } else if (IfrNvData->ISCSIDeleteAttemptList[0] != L'\0') { + AttemptList =(UINT8 *) AllocateZeroPool ((ISCSI_MAX_ATTEMPTS_NUM + 1) * sizeof (UINT8)); + if (AttemptList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + Status = IScsiGetAttemptIndexList (IfrNvData->ISCSIDeleteAttemptList, AttemptList, FALSE); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: The delete attempt list is invalid", + NULL + ); + goto Exit; + } + + // + // Mark the attempt which will be delete in the global list. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) { + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + while (AttemptList[Index] != 0) { + if (AttemptConfigData->AttemptConfigIndex == AttemptList[Index]) { + IfrNvData->DeleteAttemptList[Index2] = 1; + break; + } + Index ++; + } + Index2 ++; + Index = 0; + } + + Status = IScsiConfigDeleteAttempts (IfrNvData); + if (EFI_ERROR (Status)) { + goto Exit; + } + + FreePool (AttemptList); + + } else if (IfrNvData->ISCSIAttemptOrder[0] != L'\0') { + Status = IScsiGetAttemptIndexList (IfrNvData->ISCSIAttemptOrder, IfrNvData->DynamicOrderedList, FALSE); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: The new attempt order list is invalid", + NULL + ); + goto Exit; + } + + Status = IScsiConfigOrderAttempts (IfrNvData); + if (EFI_ERROR (Status)) { + goto Exit; + } + + } else if (IfrNvData->ISCSIMacAddr[0] != L'\0') { + NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { + NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); + IScsiMacAddrToStr ( + &NicInfo->PermanentAddress, + NicInfo->HwAddressSize, + NicInfo->VlanId, + MacString + ); + if (!StrCmp(MacString, IfrNvData->ISCSIMacAddr)) { + mPrivate->CurrentNic = NicInfo->NicIndex; + break; + } + } + + if ((NicInfo == NULL) || (NicInfo->NicIndex == 0)) { + Status = EFI_NOT_FOUND; + goto Exit; + } + + } else { + Status = IScsiConvertlfrNvDataToAttemptConfigDataByKeyword (IfrNvData, OffSet); + if (EFI_ERROR (Status)) { + goto Exit; + } + } + } + + IScsiConfigUpdateAttempt (); + +Exit: + if (InitiatorName != NULL) { + FreePool (InitiatorName); + } + + if (IfrNvData != NULL) { + FreePool (IfrNvData); + } + + return Status; +} + +/** + + This function is called to provide results data to the driver. + This data consists of a unique key that is used to identify + which data is either being passed back or being asked for. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. The format of the data tends to + vary based on the opcode that generated the callback. + @param[in] Type The type of value for the question. + @param[in, out] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. +**/ +EFI_STATUS +EFIAPI +IScsiFormCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN OUT EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + ISCSI_FORM_CALLBACK_INFO *Private; + UINTN BufferSize; + CHAR8 *IScsiName; + CHAR8 IpString[ISCSI_NAME_MAX_SIZE]; + CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN]; + UINT64 Lun; + EFI_IP_ADDRESS HostIp; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS Gateway; + ISCSI_CONFIG_IFR_NVDATA *IfrNvData; + ISCSI_CONFIG_IFR_NVDATA OldIfrNvData; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + ISCSI_NIC_INFO *NicInfo; + + NicInfo = NULL; + + if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) { + // + // Do nothing for UEFI OPEN/CLOSE Action + // + return EFI_SUCCESS; + } + + if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) { + // + // All other type return unsupported. + // + return EFI_UNSUPPORTED; + } + + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This); + + // + // Retrieve uncommitted data from Browser + // + + BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA); + IfrNvData = AllocateZeroPool (BufferSize); + if (IfrNvData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + IScsiName = (CHAR8 *) AllocateZeroPool (ISCSI_NAME_MAX_SIZE); + if (IScsiName == NULL) { + FreePool (IfrNvData); + return EFI_OUT_OF_RESOURCES; + } + + Status = EFI_SUCCESS; + + ZeroMem (&OldIfrNvData, BufferSize); + + HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData); + + CopyMem (&OldIfrNvData, IfrNvData, BufferSize); + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + switch (QuestionId) { + case KEY_ADD_ATTEMPT: + // + // Check whether iSCSI initiator name is configured already. + // + mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE; + Status = gIScsiInitiatorName.Get ( + &gIScsiInitiatorName, + &mPrivate->InitiatorNameLength, + mPrivate->InitiatorName + ); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: please configure iSCSI initiator name first!", + NULL + ); + break; + } + + Status = IScsiConfigAddAttempt (); + break; + + case KEY_DELETE_ATTEMPT: + CopyMem ( + OldIfrNvData.DeleteAttemptList, + IfrNvData->DeleteAttemptList, + sizeof (IfrNvData->DeleteAttemptList) + ); + Status = IScsiConfigDisplayDeleteAttempts (IfrNvData); + break; + + case KEY_ORDER_ATTEMPT_CONFIG: + // + // Order the attempt according to user input. + // + CopyMem ( + OldIfrNvData.DynamicOrderedList, + IfrNvData->DynamicOrderedList, + sizeof (IfrNvData->DynamicOrderedList) + ); + IScsiConfigDisplayOrderAttempts (); + break; + + default: + Status = IScsiConfigProcessDefault (QuestionId, IfrNvData); + break; + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + switch (QuestionId) { + case KEY_INITIATOR_NAME: + UnicodeStrToAsciiStrS (IfrNvData->InitiatorName, IScsiName, ISCSI_NAME_MAX_SIZE); + BufferSize = AsciiStrSize (IScsiName); + + Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid iSCSI Name!", + NULL + ); + } + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + break; + + case KEY_SAVE_ATTEMPT_CONFIG: + Status = IScsiConvertIfrNvDataToAttemptConfigData (IfrNvData, Private->Current); + if (EFI_ERROR (Status)) { + break; + } + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; + break; + + case KEY_SAVE_ORDER_CHANGES: + // + // Sync the Attempt Order to NVR. + // + Status = IScsiConfigOrderAttempts (IfrNvData); + if (EFI_ERROR (Status)) { + break; + } + + IScsiConfigUpdateAttempt (); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; + break; + + case KEY_IGNORE_ORDER_CHANGES: + CopyMem ( + IfrNvData->DynamicOrderedList, + OldIfrNvData.DynamicOrderedList, + sizeof (IfrNvData->DynamicOrderedList) + ); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; + break; + + case KEY_SAVE_DELETE_ATTEMPT: + // + // Delete the Attempt Order from NVR + // + Status = IScsiConfigDeleteAttempts (IfrNvData); + if (EFI_ERROR (Status)) { + break; + } + + IScsiConfigUpdateAttempt (); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; + break; + + case KEY_IGNORE_DELETE_ATTEMPT: + CopyMem ( + IfrNvData->DeleteAttemptList, + OldIfrNvData.DeleteAttemptList, + sizeof (IfrNvData->DeleteAttemptList) + ); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; + break; + + case KEY_IP_MODE: + switch (Value->u8) { + case IP_MODE_IP6: + NicInfo = IScsiGetNicInfoByIndex (Private->Current->NicIndex); + if(NicInfo == NULL) { + break; + } + + if(!NicInfo->Ipv6Available) { + // + // Current NIC doesn't Support IPv6, hence use IPv4. + // + IfrNvData->IpMode = IP_MODE_IP4; + + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Current NIC doesn't Support IPv6!", + NULL + ); + } + + case IP_MODE_IP4: + ZeroMem (IfrNvData->LocalIp, sizeof (IfrNvData->LocalIp)); + ZeroMem (IfrNvData->SubnetMask, sizeof (IfrNvData->SubnetMask)); + ZeroMem (IfrNvData->Gateway, sizeof (IfrNvData->Gateway)); + ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp)); + Private->Current->AutoConfigureMode = 0; + ZeroMem (&Private->Current->SessionConfigData.LocalIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->Current->SessionConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + ZeroMem (&Private->Current->SessionConfigData.Gateway, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->Current->SessionConfigData.TargetIp, sizeof (EFI_IP_ADDRESS)); + + break; + } + + break; + + case KEY_LOCAL_IP: + Status = NetLibStrToIp4 (IfrNvData->LocalIp, &HostIp.v4); + if (EFI_ERROR (Status) || + ((Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) && + !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid IP address!", + NULL + ); + + Status = EFI_INVALID_PARAMETER; + } else { + CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4)); + } + + break; + + case KEY_SUBNET_MASK: + Status = NetLibStrToIp4 (IfrNvData->SubnetMask, &SubnetMask.v4); + if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Subnet Mask!", + NULL + ); + + Status = EFI_INVALID_PARAMETER; + } else { + CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4)); + } + + break; + + case KEY_GATE_WAY: + Status = NetLibStrToIp4 (IfrNvData->Gateway, &Gateway.v4); + if (EFI_ERROR (Status) || + ((Gateway.Addr[0] != 0) && + (Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) && + !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Gateway!", + NULL + ); + Status = EFI_INVALID_PARAMETER; + } else { + CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4)); + } + + break; + + case KEY_TARGET_IP: + UnicodeStrToAsciiStrS (IfrNvData->TargetIp, IpString, sizeof (IpString)); + Status = IScsiAsciiStrToIp (IpString, IfrNvData->IpMode, &HostIp); + if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, IfrNvData->IpMode)) { + // + // The target is expressed in URL format or an invalid Ip address, just save. + // + Private->Current->SessionConfigData.DnsMode = TRUE; + ZeroMem (&Private->Current->SessionConfigData.TargetIp, sizeof (Private->Current->SessionConfigData.TargetIp)); + UnicodeStrToAsciiStrS (IfrNvData->TargetIp, Private->Current->SessionConfigData.TargetUrl, ISCSI_NAME_MAX_SIZE); + } else { + Private->Current->SessionConfigData.DnsMode = FALSE; + CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp)); + } + + break; + + case KEY_TARGET_NAME: + UnicodeStrToAsciiStrS (IfrNvData->TargetName, IScsiName, ISCSI_NAME_MAX_SIZE); + Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName)); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid iSCSI Name!", + NULL + ); + } else { + AsciiStrCpyS (Private->Current->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName); + } + + break; + + case KEY_DHCP_ENABLE: + if (IfrNvData->InitiatorInfoFromDhcp == 0) { + IfrNvData->TargetInfoFromDhcp = 0; + } + + break; + + case KEY_BOOT_LUN: + UnicodeStrToAsciiStrS (IfrNvData->BootLun, LunString, sizeof (LunString)); + Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid LUN string!", + NULL + ); + } else { + CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun)); + } + + break; + + case KEY_AUTH_TYPE: + switch (Value->u8) { + case ISCSI_AUTH_TYPE_CHAP: + IfrNvData->CHAPType = ISCSI_CHAP_UNI; + break; + default: + break; + } + + break; + + case KEY_CHAP_NAME: + UnicodeStrToAsciiStrS ( + IfrNvData->CHAPName, + Private->Current->AuthConfigData.CHAP.CHAPName, + sizeof (Private->Current->AuthConfigData.CHAP.CHAPName) + ); + break; + + case KEY_CHAP_SECRET: + UnicodeStrToAsciiStrS ( + IfrNvData->CHAPSecret, + Private->Current->AuthConfigData.CHAP.CHAPSecret, + sizeof (Private->Current->AuthConfigData.CHAP.CHAPSecret) + ); + break; + + case KEY_REVERSE_CHAP_NAME: + UnicodeStrToAsciiStrS ( + IfrNvData->ReverseCHAPName, + Private->Current->AuthConfigData.CHAP.ReverseCHAPName, + sizeof (Private->Current->AuthConfigData.CHAP.ReverseCHAPName) + ); + break; + + case KEY_REVERSE_CHAP_SECRET: + UnicodeStrToAsciiStrS ( + IfrNvData->ReverseCHAPSecret, + Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret, + sizeof (Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret) + ); + break; + + case KEY_CONFIG_ISID: + IScsiParseIsIdFromString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId); + IScsiConvertIsIdToString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId); + + break; + + default: + break; + } + } + + if (!EFI_ERROR (Status)) { + // + // Pass changed uncommitted data back to Form Browser. + // + BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA); + HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL); + } + + FreePool (IfrNvData); + FreePool (IScsiName); + + return Status; +} + + +/** + Initialize the iSCSI configuration form. + + @param[in] DriverBindingHandle The iSCSI driverbinding handle. + + @retval EFI_SUCCESS The iSCSI configuration form is initialized. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + +**/ +EFI_STATUS +IScsiConfigFormInit ( + IN EFI_HANDLE DriverBindingHandle + ) +{ + EFI_STATUS Status; + ISCSI_FORM_CALLBACK_INFO *CallbackInfo; + + CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO)); + if (CallbackInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE; + CallbackInfo->Current = NULL; + + CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig; + CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig; + CallbackInfo->ConfigAccess.Callback = IScsiFormCallback; + + // + // Install Device Path Protocol and Config Access protocol to driver handle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &CallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mIScsiHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &CallbackInfo->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data. + // + CallbackInfo->RegisteredHandle = HiiAddPackages ( + &gIScsiConfigGuid, + CallbackInfo->DriverHandle, + IScsiDxeStrings, + IScsiConfigVfrBin, + NULL + ); + if (CallbackInfo->RegisteredHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + CallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mIScsiHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &CallbackInfo->ConfigAccess, + NULL + ); + FreePool(CallbackInfo); + return EFI_OUT_OF_RESOURCES; + } + + mCallbackInfo = CallbackInfo; + + return EFI_SUCCESS; +} + + +/** + Unload the iSCSI configuration form, this includes: delete all the iSCSI + configuration entries, uninstall the form callback protocol, and + free the resources used. + + @param[in] DriverBindingHandle The iSCSI driverbinding handle. + + @retval EFI_SUCCESS The iSCSI configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +IScsiConfigFormUnload ( + IN EFI_HANDLE DriverBindingHandle + ) +{ + ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; + ISCSI_NIC_INFO *NicInfo; + LIST_ENTRY *Entry; + EFI_STATUS Status; + + while (!IsListEmpty (&mPrivate->AttemptConfigs)) { + Entry = NetListRemoveHead (&mPrivate->AttemptConfigs); + AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + FreePool (AttemptConfigData); + mPrivate->AttemptCount--; + } + + ASSERT (mPrivate->AttemptCount == 0); + + while (!IsListEmpty (&mPrivate->NicInfoList)) { + Entry = NetListRemoveHead (&mPrivate->NicInfoList); + NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); + FreePool (NicInfo); + mPrivate->NicCount--; + } + + ASSERT (mPrivate->NicCount == 0); + + FreePool (mPrivate); + mPrivate = NULL; + + // + // Remove HII package list. + // + HiiRemovePackages (mCallbackInfo->RegisteredHandle); + + // + // Uninstall Device Path Protocol and Config Access protocol. + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + mCallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mIScsiHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &mCallbackInfo->ConfigAccess, + NULL + ); + + FreePool (mCallbackInfo); + + return Status; +} -- cgit v1.2.3