/** @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; | |
} |