summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiConfig.c3934
1 files changed, 3934 insertions, 0 deletions
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.<BR>
+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
+ <ConfigString> 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 <Number> 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 <ConfigAltResp> 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 <ConfigAltResp> 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=<StringToken>". That <StringToken> (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
+ <ConfigRequest> 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
+ <MultiConfigRequest> 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
+ <ConfigAltResp> 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 <ConfigHdr> 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 <ConfigResp> 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 <ConfigHdr> 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 <BlockConfig>
+ 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
+ <ConfigString> 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 <ConfigHdr>.
+ // 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 <ConfigResp> 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;
+}