Home | History | Annotate | Download | only in IScsiDxe
      1 /** @file
      2   Helper functions for configuring or getting the parameters relating to iSCSI.
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IScsiImpl.h"
     16 
     17 CHAR16          mVendorStorageName[]     = L"ISCSI_CONFIG_IFR_NVDATA";
     18 BOOLEAN         mIScsiDeviceListUpdated  = FALSE;
     19 UINTN           mNumberOfIScsiDevices    = 0;
     20 ISCSI_FORM_CALLBACK_INFO  *mCallbackInfo = NULL;
     21 
     22 HII_VENDOR_DEVICE_PATH  mIScsiHiiVendorDevicePath = {
     23   {
     24     {
     25       HARDWARE_DEVICE_PATH,
     26       HW_VENDOR_DP,
     27       {
     28         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     29         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     30       }
     31     },
     32     ISCSI_CONFIG_GUID
     33   },
     34   {
     35     END_DEVICE_PATH_TYPE,
     36     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     37     {
     38       (UINT8) (END_DEVICE_PATH_LENGTH),
     39       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     40     }
     41   }
     42 };
     43 
     44 
     45 /**
     46   Convert the IP address into a dotted string.
     47 
     48   @param[in]  Ip        The IP address.
     49   @param[in]  Ipv6Flag  Indicates whether the IP address is version 4 or version 6.
     50   @param[out] Str       The formatted IP string.
     51 
     52 **/
     53 VOID
     54 IScsiIpToStr (
     55   IN  EFI_IP_ADDRESS    *Ip,
     56   IN  BOOLEAN           Ipv6Flag,
     57   OUT CHAR16            *Str
     58   )
     59 {
     60   EFI_IPv4_ADDRESS      *Ip4;
     61   EFI_IPv6_ADDRESS      *Ip6;
     62   UINTN                 Index;
     63   BOOLEAN               Short;
     64   UINTN                 Number;
     65   CHAR16                FormatString[8];
     66 
     67   if (!Ipv6Flag) {
     68     Ip4 = &Ip->v4;
     69 
     70     UnicodeSPrint (
     71       Str,
     72       (UINTN) 2 * IP4_STR_MAX_SIZE,
     73       L"%d.%d.%d.%d",
     74       (UINTN) Ip4->Addr[0],
     75       (UINTN) Ip4->Addr[1],
     76       (UINTN) Ip4->Addr[2],
     77       (UINTN) Ip4->Addr[3]
     78       );
     79 
     80     return ;
     81   }
     82 
     83   Ip6   = &Ip->v6;
     84   Short = FALSE;
     85 
     86   for (Index = 0; Index < 15; Index = Index + 2) {
     87     if (!Short &&
     88         Index % 2 == 0 &&
     89         Ip6->Addr[Index] == 0 &&
     90         Ip6->Addr[Index + 1] == 0
     91         ) {
     92       //
     93       // Deal with the case of ::.
     94       //
     95       if (Index == 0) {
     96         *Str       = L':';
     97         *(Str + 1) = L':';
     98         Str        = Str + 2;
     99       } else {
    100         *Str       = L':';
    101         Str        = Str + 1;
    102       }
    103 
    104       while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {
    105         Index = Index + 2;
    106       }
    107 
    108       Short = TRUE;
    109 
    110       if (Index == 16) {
    111         //
    112         // :: is at the end of the address.
    113         //
    114         *Str = L'\0';
    115         break;
    116       }
    117     }
    118 
    119     ASSERT (Index < 15);
    120 
    121     if (Ip6->Addr[Index] == 0) {
    122       Number = UnicodeSPrint (Str, 2 * IP_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);
    123     } else {
    124       if (Ip6->Addr[Index + 1] < 0x10) {
    125         CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));
    126       } else {
    127         CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));
    128       }
    129 
    130       Number = UnicodeSPrint (
    131                  Str,
    132                  2 * IP_STR_MAX_SIZE,
    133                  (CONST CHAR16 *) FormatString,
    134                  (UINTN) Ip6->Addr[Index],
    135                  (UINTN) Ip6->Addr[Index + 1]
    136                  );
    137     }
    138 
    139     Str = Str + Number;
    140 
    141     if (Index + 2 == 16) {
    142       *Str = L'\0';
    143       if (*(Str - 1) == L':') {
    144         *(Str - 1) = L'\0';
    145       }
    146     }
    147   }
    148 }
    149 
    150 /**
    151   Check whether the input IP address is valid.
    152 
    153   @param[in]  Ip        The IP address.
    154   @param[in]  IpMode    Indicates iSCSI running on IP4 or IP6 stack.
    155 
    156   @retval     TRUE      The input IP address is valid.
    157   @retval     FALSE     Otherwise
    158 
    159 **/
    160 BOOLEAN
    161 IpIsUnicast (
    162   IN EFI_IP_ADDRESS *Ip,
    163   IN  UINT8          IpMode
    164   )
    165 {
    166   if (IpMode == IP_MODE_IP4) {
    167     return NetIp4IsUnicast (NTOHL (Ip->Addr[0]), 0);
    168   } else if (IpMode == IP_MODE_IP6) {
    169     return NetIp6IsValidUnicast (&Ip->v6);
    170   } else {
    171     DEBUG ((DEBUG_ERROR, "IpMode %d is invalid when configuring the iSCSI target IP!\n", IpMode));
    172     return FALSE;
    173   }
    174 }
    175 
    176 /**
    177   Parse IsId in string format and convert it to binary.
    178 
    179   @param[in]        String  The buffer of the string to be parsed.
    180   @param[in, out]   IsId    The buffer to store IsId.
    181 
    182   @retval EFI_SUCCESS              The operation finished successfully.
    183   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    184 
    185 **/
    186 EFI_STATUS
    187 IScsiParseIsIdFromString (
    188   IN CONST CHAR16                    *String,
    189   IN OUT   UINT8                     *IsId
    190   )
    191 {
    192   UINT8                          Index;
    193   CHAR16                         *IsIdStr;
    194   CHAR16                         TempStr[3];
    195   UINTN                          NodeVal;
    196   CHAR16                         PortString[ISCSI_NAME_IFR_MAX_SIZE];
    197   EFI_INPUT_KEY                  Key;
    198 
    199   if ((String == NULL) || (IsId == NULL)) {
    200     return EFI_INVALID_PARAMETER;
    201   }
    202 
    203   IsIdStr = (CHAR16 *) String;
    204 
    205   if (StrLen (IsIdStr) != 6) {
    206     UnicodeSPrint (
    207       PortString,
    208       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
    209       L"Error! Input is incorrect, please input 6 hex numbers!\n"
    210       );
    211 
    212     CreatePopUp (
    213       EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    214       &Key,
    215       PortString,
    216       NULL
    217       );
    218 
    219     return EFI_INVALID_PARAMETER;
    220   }
    221 
    222   for (Index = 3; Index < 6; Index++) {
    223     CopyMem (TempStr, IsIdStr, sizeof (TempStr));
    224     TempStr[2] = L'\0';
    225 
    226     //
    227     // Convert the string to IsId. StrHexToUintn stops at the first character
    228     // that is not a valid hex character, '\0' here.
    229     //
    230     NodeVal = StrHexToUintn (TempStr);
    231 
    232     IsId[Index] = (UINT8) NodeVal;
    233 
    234     IsIdStr = IsIdStr + 2;
    235   }
    236 
    237   return EFI_SUCCESS;
    238 }
    239 
    240 /**
    241   Convert IsId from binary to string format.
    242 
    243   @param[out]      String  The buffer to store the converted string.
    244   @param[in]       IsId    The buffer to store IsId.
    245 
    246   @retval EFI_SUCCESS              The string converted successfully.
    247   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    248 
    249 **/
    250 EFI_STATUS
    251 IScsiConvertIsIdToString (
    252   OUT CHAR16                         *String,
    253   IN  UINT8                          *IsId
    254   )
    255 {
    256   UINT8                          Index;
    257   UINTN                          Number;
    258 
    259   if ((String == NULL) || (IsId == NULL)) {
    260     return EFI_INVALID_PARAMETER;
    261   }
    262 
    263   for (Index = 0; Index < 6; Index++) {
    264     if (IsId[Index] <= 0xF) {
    265       Number = UnicodeSPrint (
    266                  String,
    267                  2 * ISID_CONFIGURABLE_STORAGE,
    268                  L"0%X",
    269                  (UINTN) IsId[Index]
    270                  );
    271     } else {
    272       Number = UnicodeSPrint (
    273                  String,
    274                  2 * ISID_CONFIGURABLE_STORAGE,
    275                  L"%X",
    276                  (UINTN) IsId[Index]
    277                  );
    278 
    279     }
    280 
    281     String = String + Number;
    282   }
    283 
    284   *String = L'\0';
    285 
    286   return EFI_SUCCESS;
    287 }
    288 
    289 /**
    290   Get the attempt config data from global structure by the ConfigIndex.
    291 
    292   @param[in]  AttemptConfigIndex     The unique index indicates the attempt.
    293 
    294   @return       Pointer to the attempt config data.
    295   @retval NULL  The attempt configuration data cannot be found.
    296 
    297 **/
    298 ISCSI_ATTEMPT_CONFIG_NVDATA *
    299 IScsiConfigGetAttemptByConfigIndex (
    300   IN UINT8                     AttemptConfigIndex
    301   )
    302 {
    303   LIST_ENTRY                   *Entry;
    304   ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt;
    305 
    306   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
    307     Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
    308     if (Attempt->AttemptConfigIndex == AttemptConfigIndex) {
    309       return Attempt;
    310     }
    311   }
    312 
    313   return NULL;
    314 }
    315 
    316 
    317 /**
    318   Get the existing attempt config data from global structure by the NicIndex.
    319 
    320   @param[in]  NewAttempt         The created new attempt
    321   @param[in]  IScsiMode          The IScsi Mode of the new attempt, Enabled or
    322                                  Enabled for MPIO.
    323 
    324   @return                        Pointer to the existing attempt config data which
    325                                  has the same NICIndex as the new created attempt.
    326   @retval     NULL               The attempt with NicIndex does not exist.
    327 
    328 **/
    329 ISCSI_ATTEMPT_CONFIG_NVDATA *
    330 IScsiConfigGetAttemptByNic (
    331   IN ISCSI_ATTEMPT_CONFIG_NVDATA *NewAttempt,
    332   IN UINT8                       IScsiMode
    333   )
    334 {
    335   LIST_ENTRY                   *Entry;
    336   ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt;
    337 
    338   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
    339     Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
    340     if (Attempt != NewAttempt && Attempt->NicIndex == NewAttempt->NicIndex &&
    341         Attempt->SessionConfigData.Enabled == IScsiMode) {
    342       return Attempt;
    343     }
    344   }
    345 
    346   return NULL;
    347 }
    348 
    349 
    350 /**
    351   Convert the iSCSI configuration data into the IFR data.
    352 
    353   @param[in]       Attempt                The iSCSI attempt config data.
    354   @param[in, out]  IfrNvData              The IFR nv data.
    355 
    356 **/
    357 VOID
    358 IScsiConvertAttemptConfigDataToIfrNvData (
    359   IN ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt,
    360   IN OUT ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
    361   )
    362 {
    363   ISCSI_SESSION_CONFIG_NVDATA   *SessionConfigData;
    364   ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;
    365   EFI_IP_ADDRESS                Ip;
    366 
    367   //
    368   // Normal session configuration parameters.
    369   //
    370   SessionConfigData                 = &Attempt->SessionConfigData;
    371   IfrNvData->Enabled                = SessionConfigData->Enabled;
    372   IfrNvData->IpMode                 = SessionConfigData->IpMode;
    373 
    374   IfrNvData->InitiatorInfoFromDhcp  = SessionConfigData->InitiatorInfoFromDhcp;
    375   IfrNvData->TargetInfoFromDhcp     = SessionConfigData->TargetInfoFromDhcp;
    376   IfrNvData->TargetPort             = SessionConfigData->TargetPort;
    377 
    378   if (IfrNvData->IpMode == IP_MODE_IP4) {
    379     CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
    380     IScsiIpToStr (&Ip, FALSE, IfrNvData->LocalIp);
    381     CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    382     IScsiIpToStr (&Ip, FALSE, IfrNvData->SubnetMask);
    383     CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS));
    384     IScsiIpToStr (&Ip, FALSE, IfrNvData->Gateway);
    385     CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS));
    386     IScsiIpToStr (&Ip, FALSE, IfrNvData->TargetIp);
    387   } else if (IfrNvData->IpMode == IP_MODE_IP6) {
    388     ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
    389     IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp);
    390     IScsiIpToStr (&Ip, TRUE, IfrNvData->TargetIp);
    391   }
    392 
    393   AsciiStrToUnicodeStr (SessionConfigData->TargetName, IfrNvData->TargetName);
    394   IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);
    395   IScsiConvertIsIdToString (IfrNvData->IsId, SessionConfigData->IsId);
    396 
    397   IfrNvData->ConnectRetryCount = SessionConfigData->ConnectRetryCount;
    398   IfrNvData->ConnectTimeout    = SessionConfigData->ConnectTimeout;
    399 
    400   //
    401   // Authentication parameters.
    402   //
    403   IfrNvData->AuthenticationType = Attempt->AuthenticationType;
    404 
    405   if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
    406     AuthConfigData      = &Attempt->AuthConfigData.CHAP;
    407     IfrNvData->CHAPType = AuthConfigData->CHAPType;
    408     AsciiStrToUnicodeStr (AuthConfigData->CHAPName, IfrNvData->CHAPName);
    409     AsciiStrToUnicodeStr (AuthConfigData->CHAPSecret, IfrNvData->CHAPSecret);
    410     AsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPName, IfrNvData->ReverseCHAPName);
    411     AsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);
    412   }
    413 
    414   //
    415   // Other parameters.
    416   //
    417   AsciiStrToUnicodeStr (Attempt->AttemptName, IfrNvData->AttemptName);
    418 }
    419 
    420 /**
    421   Convert the IFR data to iSCSI configuration data.
    422 
    423   @param[in]       IfrNvData              Point to ISCSI_CONFIG_IFR_NVDATA.
    424   @param[in, out]  Attempt                The iSCSI attempt config data.
    425 
    426   @retval EFI_INVALID_PARAMETER  Any input or configured parameter is invalid.
    427   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
    428   @retval EFI_OUT_OF_RESOURCES   The operation is failed due to lack of resources.
    429   @retval EFI_ABORTED            The operation is aborted.
    430   @retval EFI_SUCCESS            The operation is completed successfully.
    431 
    432 **/
    433 EFI_STATUS
    434 IScsiConvertIfrNvDataToAttemptConfigData (
    435   IN ISCSI_CONFIG_IFR_NVDATA          *IfrNvData,
    436   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt
    437   )
    438 {
    439   EFI_IP_ADDRESS              HostIp;
    440   EFI_IP_ADDRESS              SubnetMask;
    441   EFI_IP_ADDRESS              Gateway;
    442   CHAR16                      *MacString;
    443   CHAR16                      *AttemptName1;
    444   CHAR16                      *AttemptName2;
    445   ISCSI_ATTEMPT_CONFIG_NVDATA *ExistAttempt;
    446   ISCSI_ATTEMPT_CONFIG_NVDATA *SameNicAttempt;
    447   CHAR16                      IScsiMode[64];
    448   CHAR16                      IpMode[64];
    449   ISCSI_NIC_INFO              *NicInfo;
    450   EFI_INPUT_KEY               Key;
    451   UINT8                       *AttemptConfigOrder;
    452   UINTN                       AttemptConfigOrderSize;
    453   UINT8                       *AttemptOrderTmp;
    454   UINTN                       TotalNumber;
    455   EFI_STATUS                  Status;
    456 
    457   if (IfrNvData == NULL || Attempt == NULL) {
    458     return EFI_INVALID_PARAMETER;
    459   }
    460 
    461   //
    462   // Update those fields which don't have INTERACTIVE attribute.
    463   //
    464   Attempt->SessionConfigData.ConnectRetryCount     = IfrNvData->ConnectRetryCount;
    465   Attempt->SessionConfigData.ConnectTimeout        = IfrNvData->ConnectTimeout;
    466   Attempt->SessionConfigData.IpMode                = IfrNvData->IpMode;
    467 
    468   if (IfrNvData->IpMode < IP_MODE_AUTOCONFIG) {
    469     Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;
    470     Attempt->SessionConfigData.TargetPort            = IfrNvData->TargetPort;
    471 
    472     if (Attempt->SessionConfigData.TargetPort == 0) {
    473       Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
    474     }
    475 
    476     Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;
    477   }
    478 
    479   Attempt->AuthenticationType = IfrNvData->AuthenticationType;
    480 
    481   if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
    482     Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->CHAPType;
    483   }
    484 
    485   //
    486   // Only do full parameter validation if iSCSI is enabled on this device.
    487   //
    488   if (IfrNvData->Enabled != ISCSI_DISABLED) {
    489     if (Attempt->SessionConfigData.ConnectTimeout < CONNECT_MIN_TIMEOUT) {
    490       CreatePopUp (
    491         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    492         &Key,
    493         L"Connection Establishing Timeout is less than minimum value 100ms.",
    494         NULL
    495         );
    496 
    497       return EFI_INVALID_PARAMETER;
    498     }
    499 
    500     //
    501     // Validate the address configuration of the Initiator if DHCP isn't
    502     // deployed.
    503     //
    504     if (!Attempt->SessionConfigData.InitiatorInfoFromDhcp) {
    505       CopyMem (&HostIp.v4, &Attempt->SessionConfigData.LocalIp, sizeof (HostIp.v4));
    506       CopyMem (&SubnetMask.v4, &Attempt->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
    507       CopyMem (&Gateway.v4, &Attempt->SessionConfigData.Gateway, sizeof (Gateway.v4));
    508 
    509       if ((Gateway.Addr[0] != 0)) {
    510         if (SubnetMask.Addr[0] == 0) {
    511           CreatePopUp (
    512             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    513             &Key,
    514             L"Gateway address is set but subnet mask is zero.",
    515             NULL
    516             );
    517 
    518           return EFI_INVALID_PARAMETER;
    519         } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
    520           CreatePopUp (
    521             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    522             &Key,
    523             L"Local IP and Gateway are not in the same subnet.",
    524             NULL
    525             );
    526 
    527           return EFI_INVALID_PARAMETER;
    528         }
    529       }
    530     }
    531     //
    532     // Validate target configuration if DHCP isn't deployed.
    533     //
    534     if (!Attempt->SessionConfigData.TargetInfoFromDhcp && Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {
    535       if (!IpIsUnicast (&Attempt->SessionConfigData.TargetIp, IfrNvData->IpMode)) {
    536         CreatePopUp (
    537           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    538           &Key,
    539           L"Target IP is invalid!",
    540           NULL
    541           );
    542         return EFI_INVALID_PARAMETER;
    543       }
    544 
    545       //
    546       // Validate iSCSI target name configuration again:
    547       // The format of iSCSI target name is already verified in IScsiFormCallback() when
    548       // user input the name; here we only check the case user does not input the name.
    549       //
    550       if (Attempt->SessionConfigData.TargetName[0] == '\0') {
    551         CreatePopUp (
    552           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    553           &Key,
    554           L"iSCSI target name is NULL!",
    555           NULL
    556           );
    557         return EFI_INVALID_PARAMETER;
    558       }
    559     }
    560 
    561 
    562     //
    563     // Validate the authentication info.
    564     //
    565     if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
    566       if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
    567         CreatePopUp (
    568           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    569           &Key,
    570           L"CHAP Name or CHAP Secret is invalid!",
    571           NULL
    572           );
    573 
    574         return EFI_INVALID_PARAMETER;
    575       }
    576 
    577       if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
    578           ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
    579           ) {
    580         CreatePopUp (
    581           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    582           &Key,
    583           L"Reverse CHAP Name or Reverse CHAP Secret is invalid!",
    584           NULL
    585           );
    586         return EFI_INVALID_PARAMETER;
    587       }
    588     }
    589 
    590     //
    591     // Check whether this attempt uses NIC which is already used by existing attempt.
    592     //
    593     SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled);
    594     if (SameNicAttempt != NULL) {
    595       AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_MAX_SIZE * sizeof (CHAR16));
    596       if (AttemptName1 == NULL) {
    597         return EFI_OUT_OF_RESOURCES;
    598       }
    599 
    600       AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_MAX_SIZE * sizeof (CHAR16));
    601       if (AttemptName2 == NULL) {
    602         FreePool (AttemptName1);
    603         return EFI_OUT_OF_RESOURCES;
    604       }
    605 
    606       AsciiStrToUnicodeStr (Attempt->AttemptName, AttemptName1);
    607       if (StrLen (AttemptName1) > ATTEMPT_NAME_SIZE) {
    608         CopyMem (&AttemptName1[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));
    609       }
    610 
    611       AsciiStrToUnicodeStr (SameNicAttempt->AttemptName, AttemptName2);
    612       if (StrLen (AttemptName2) > ATTEMPT_NAME_SIZE) {
    613         CopyMem (&AttemptName2[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));
    614       }
    615 
    616       UnicodeSPrint (
    617         mPrivate->PortString,
    618         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
    619         L"Warning! Attempt \"%s\" uses same NIC as Attempt \"%s\".",
    620         AttemptName1,
    621         AttemptName2
    622         );
    623 
    624       CreatePopUp (
    625         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    626         &Key,
    627         mPrivate->PortString,
    628         NULL
    629         );
    630 
    631       FreePool (AttemptName1);
    632       FreePool (AttemptName2);
    633     }
    634   }
    635 
    636   //
    637   // Update the iSCSI Mode data and record it in attempt help info.
    638   //
    639   Attempt->SessionConfigData.Enabled = IfrNvData->Enabled;
    640   if (IfrNvData->Enabled == ISCSI_DISABLED) {
    641     UnicodeSPrint (IScsiMode, 64, L"Disabled");
    642   } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
    643     UnicodeSPrint (IScsiMode, 64, L"Enabled");
    644   } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
    645     UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
    646   }
    647 
    648   if (IfrNvData->IpMode == IP_MODE_IP4) {
    649     UnicodeSPrint (IpMode, 64, L"IP4");
    650   } else if (IfrNvData->IpMode == IP_MODE_IP6) {
    651     UnicodeSPrint (IpMode, 64, L"IP6");
    652   } else if (IfrNvData->IpMode == IP_MODE_AUTOCONFIG) {
    653     UnicodeSPrint (IpMode, 64, L"Autoconfigure");
    654   }
    655 
    656   NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);
    657   if (NicInfo == NULL) {
    658     return EFI_NOT_FOUND;
    659   }
    660 
    661   MacString = (CHAR16 *) AllocateZeroPool (ISCSI_MAX_MAC_STRING_LEN * sizeof (CHAR16));
    662   if (MacString == NULL) {
    663     return EFI_OUT_OF_RESOURCES;
    664   }
    665 
    666   AsciiStrToUnicodeStr (Attempt->MacString, MacString);
    667 
    668   UnicodeSPrint (
    669     mPrivate->PortString,
    670     (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
    671     L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
    672     MacString,
    673     NicInfo->BusNumber,
    674     NicInfo->DeviceNumber,
    675     NicInfo->FunctionNumber,
    676     IScsiMode,
    677     IpMode
    678     );
    679 
    680   Attempt->AttemptTitleHelpToken = HiiSetString (
    681                                      mCallbackInfo->RegisteredHandle,
    682                                      Attempt->AttemptTitleHelpToken,
    683                                      mPrivate->PortString,
    684                                      NULL
    685                                      );
    686   if (Attempt->AttemptTitleHelpToken == 0) {
    687     FreePool (MacString);
    688     return EFI_OUT_OF_RESOURCES;
    689   }
    690 
    691   //
    692   // Check whether this attempt is an existing one.
    693   //
    694   ExistAttempt = IScsiConfigGetAttemptByConfigIndex (Attempt->AttemptConfigIndex);
    695   if (ExistAttempt != NULL) {
    696     ASSERT (ExistAttempt == Attempt);
    697 
    698     if (IfrNvData->Enabled == ISCSI_DISABLED &&
    699         Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
    700 
    701       //
    702       // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled".
    703       //
    704       if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
    705         if (mPrivate->MpioCount < 1) {
    706           return EFI_ABORTED;
    707         }
    708 
    709         if (--mPrivate->MpioCount == 0) {
    710           mPrivate->EnableMpio = FALSE;
    711         }
    712       } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
    713         if (mPrivate->SinglePathCount < 1) {
    714           return EFI_ABORTED;
    715         }
    716         mPrivate->SinglePathCount--;
    717       }
    718 
    719     } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO &&
    720                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
    721       //
    722       // User updates the Attempt from "Enabled" to "Enabled for MPIO".
    723       //
    724       if (mPrivate->SinglePathCount < 1) {
    725         return EFI_ABORTED;
    726       }
    727 
    728       mPrivate->EnableMpio = TRUE;
    729       mPrivate->MpioCount++;
    730       mPrivate->SinglePathCount--;
    731 
    732     } else if (IfrNvData->Enabled == ISCSI_ENABLED &&
    733                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
    734       //
    735       // User updates the Attempt from "Enabled for MPIO" to "Enabled".
    736       //
    737       if (mPrivate->MpioCount < 1) {
    738         return EFI_ABORTED;
    739       }
    740 
    741       if (--mPrivate->MpioCount == 0) {
    742         mPrivate->EnableMpio = FALSE;
    743       }
    744       mPrivate->SinglePathCount++;
    745 
    746     } else if (IfrNvData->Enabled != ISCSI_DISABLED &&
    747                Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {
    748       //
    749       // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO".
    750       //
    751       if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
    752         mPrivate->EnableMpio = TRUE;
    753         mPrivate->MpioCount++;
    754 
    755       } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
    756         mPrivate->SinglePathCount++;
    757       }
    758     }
    759 
    760   } else if (ExistAttempt == NULL) {
    761     //
    762     // When a new attempt is created, pointer of the attempt is saved to
    763     // mPrivate->NewAttempt, and also saved to mCallbackInfo->Current in
    764     // IScsiConfigProcessDefault. If input Attempt does not match any existing
    765     // attempt, it should be a new created attempt. Save it to system now.
    766     //
    767     ASSERT (Attempt == mPrivate->NewAttempt);
    768 
    769     //
    770     // Save current order number for this attempt.
    771     //
    772     AttemptConfigOrder = IScsiGetVariableAndSize (
    773                            L"AttemptOrder",
    774                            &gIScsiConfigGuid,
    775                            &AttemptConfigOrderSize
    776                            );
    777 
    778     TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);
    779     TotalNumber++;
    780 
    781     //
    782     // Append the new created attempt order to the end.
    783     //
    784     AttemptOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8));
    785     if (AttemptOrderTmp == NULL) {
    786       if (AttemptConfigOrder != NULL) {
    787         FreePool (AttemptConfigOrder);
    788       }
    789       return EFI_OUT_OF_RESOURCES;
    790     }
    791 
    792     if (AttemptConfigOrder != NULL) {
    793       CopyMem (AttemptOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize);
    794       FreePool (AttemptConfigOrder);
    795     }
    796 
    797     AttemptOrderTmp[TotalNumber - 1] = Attempt->AttemptConfigIndex;
    798     AttemptConfigOrder               = AttemptOrderTmp;
    799     AttemptConfigOrderSize           = TotalNumber * sizeof (UINT8);
    800 
    801     Status = gRT->SetVariable (
    802                     L"AttemptOrder",
    803                     &gIScsiConfigGuid,
    804                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    805                     AttemptConfigOrderSize,
    806                     AttemptConfigOrder
    807                     );
    808     FreePool (AttemptConfigOrder);
    809     if (EFI_ERROR (Status)) {
    810       return Status;
    811     }
    812 
    813     //
    814     // Insert new created attempt to array.
    815     //
    816     InsertTailList (&mPrivate->AttemptConfigs, &Attempt->Link);
    817     mPrivate->AttemptCount++;
    818     //
    819     // Reset mPrivate->NewAttempt to NULL, which indicates none attempt is created
    820     // but not saved now.
    821     //
    822     mPrivate->NewAttempt = NULL;
    823 
    824     if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
    825       //
    826       // This new Attempt is enabled for MPIO; enable the multipath mode.
    827       //
    828       mPrivate->EnableMpio = TRUE;
    829       mPrivate->MpioCount++;
    830     } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
    831       mPrivate->SinglePathCount++;
    832     }
    833 
    834     IScsiConfigUpdateAttempt ();
    835   }
    836 
    837   //
    838   // Record the user configuration information in NVR.
    839   //
    840   UnicodeSPrint (
    841     mPrivate->PortString,
    842     (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
    843     L"%s%d",
    844     MacString,
    845     (UINTN) Attempt->AttemptConfigIndex
    846     );
    847 
    848   FreePool (MacString);
    849 
    850   return gRT->SetVariable (
    851                 mPrivate->PortString,
    852                 &gEfiIScsiInitiatorNameProtocolGuid,
    853                 ISCSI_CONFIG_VAR_ATTR,
    854                 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
    855                 Attempt
    856                 );
    857 }
    858 
    859 /**
    860   Create Hii Extend Label OpCode as the start opcode and end opcode. It is
    861   a help function.
    862 
    863   @param[in]  StartLabelNumber   The number of start label.
    864   @param[out] StartOpCodeHandle  Points to the start opcode handle.
    865   @param[out] StartLabel         Points to the created start opcode.
    866   @param[out] EndOpCodeHandle    Points to the end opcode handle.
    867   @param[out] EndLabel           Points to the created end opcode.
    868 
    869   @retval EFI_OUT_OF_RESOURCES   Do not have sufficient resource to finish this
    870                                  operation.
    871   @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.
    872   @retval EFI_SUCCESS            The operation is completed successfully.
    873 
    874 **/
    875 EFI_STATUS
    876 IScsiCreateOpCode (
    877   IN  UINT16                        StartLabelNumber,
    878   OUT VOID                          **StartOpCodeHandle,
    879   OUT EFI_IFR_GUID_LABEL            **StartLabel,
    880   OUT VOID                          **EndOpCodeHandle,
    881   OUT EFI_IFR_GUID_LABEL            **EndLabel
    882   )
    883 {
    884   EFI_STATUS                        Status;
    885   EFI_IFR_GUID_LABEL                *InternalStartLabel;
    886   EFI_IFR_GUID_LABEL                *InternalEndLabel;
    887 
    888   if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {
    889     return EFI_INVALID_PARAMETER;
    890   }
    891 
    892   *StartOpCodeHandle = NULL;
    893   *EndOpCodeHandle   = NULL;
    894   Status             = EFI_OUT_OF_RESOURCES;
    895 
    896   //
    897   // Initialize the container for dynamic opcodes.
    898   //
    899   *StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    900   if (*StartOpCodeHandle == NULL) {
    901     return Status;
    902   }
    903 
    904   *EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    905   if (*EndOpCodeHandle == NULL) {
    906     goto Exit;
    907   }
    908 
    909   //
    910   // Create Hii Extend Label OpCode as the start opcode.
    911   //
    912   InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    913                                                 *StartOpCodeHandle,
    914                                                 &gEfiIfrTianoGuid,
    915                                                 NULL,
    916                                                 sizeof (EFI_IFR_GUID_LABEL)
    917                                                 );
    918   if (InternalStartLabel == NULL) {
    919     goto Exit;
    920   }
    921 
    922   InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    923   InternalStartLabel->Number       = StartLabelNumber;
    924 
    925   //
    926   // Create Hii Extend Label OpCode as the end opcode.
    927   //
    928   InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    929                                               *EndOpCodeHandle,
    930                                               &gEfiIfrTianoGuid,
    931                                               NULL,
    932                                               sizeof (EFI_IFR_GUID_LABEL)
    933                                               );
    934   if (InternalEndLabel == NULL) {
    935     goto Exit;
    936   }
    937 
    938   InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    939   InternalEndLabel->Number       = LABEL_END;
    940 
    941   *StartLabel = InternalStartLabel;
    942   *EndLabel   = InternalEndLabel;
    943 
    944   return EFI_SUCCESS;
    945 
    946 Exit:
    947 
    948   if (*StartOpCodeHandle != NULL) {
    949     HiiFreeOpCodeHandle (*StartOpCodeHandle);
    950   }
    951 
    952   if (*EndOpCodeHandle != NULL) {
    953     HiiFreeOpCodeHandle (*EndOpCodeHandle);
    954   }
    955 
    956   return Status;
    957 }
    958 
    959 /**
    960   Callback function when user presses "Add an Attempt".
    961 
    962   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
    963                                  operation.
    964   @retval EFI_SUCCESS            The operation is completed successfully.
    965 
    966 **/
    967 EFI_STATUS
    968 IScsiConfigAddAttempt (
    969   VOID
    970   )
    971 {
    972   LIST_ENTRY                    *Entry;
    973   ISCSI_NIC_INFO                *NicInfo;
    974   EFI_STRING_ID                 PortTitleToken;
    975   EFI_STRING_ID                 PortTitleHelpToken;
    976   CHAR16                        MacString[ISCSI_MAX_MAC_STRING_LEN];
    977   EFI_STATUS                    Status;
    978   VOID                          *StartOpCodeHandle;
    979   EFI_IFR_GUID_LABEL            *StartLabel;
    980   VOID                          *EndOpCodeHandle;
    981   EFI_IFR_GUID_LABEL            *EndLabel;
    982 
    983   Status = IScsiCreateOpCode (
    984              MAC_ENTRY_LABEL,
    985              &StartOpCodeHandle,
    986              &StartLabel,
    987              &EndOpCodeHandle,
    988              &EndLabel
    989              );
    990   if (EFI_ERROR (Status)) {
    991     return Status;
    992   }
    993 
    994   //
    995   // Ask user to select a MAC for this attempt.
    996   //
    997   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
    998     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
    999     IScsiMacAddrToStr (
   1000       &NicInfo->PermanentAddress,
   1001       NicInfo->HwAddressSize,
   1002       NicInfo->VlanId,
   1003       MacString
   1004       );
   1005 
   1006     UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"MAC %s", MacString);
   1007     PortTitleToken = HiiSetString (
   1008                        mCallbackInfo->RegisteredHandle,
   1009                        0,
   1010                        mPrivate->PortString,
   1011                        NULL
   1012                        );
   1013     if (PortTitleToken == 0) {
   1014       Status = EFI_INVALID_PARAMETER;
   1015       goto Exit;
   1016     }
   1017 
   1018     UnicodeSPrint (
   1019       mPrivate->PortString,
   1020       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
   1021       L"PFA: Bus %d | Dev %d | Func %d",
   1022       NicInfo->BusNumber,
   1023       NicInfo->DeviceNumber,
   1024       NicInfo->FunctionNumber
   1025       );
   1026     PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, mPrivate->PortString, NULL);
   1027     if (PortTitleHelpToken == 0) {
   1028       Status = EFI_INVALID_PARAMETER;
   1029       goto Exit;
   1030     }
   1031 
   1032     HiiCreateGotoOpCode (
   1033       StartOpCodeHandle,                      // Container for dynamic created opcodes
   1034       FORMID_ATTEMPT_FORM,
   1035       PortTitleToken,
   1036       PortTitleHelpToken,
   1037       EFI_IFR_FLAG_CALLBACK,                  // Question flag
   1038       (UINT16) (KEY_MAC_ENTRY_BASE + NicInfo->NicIndex)
   1039       );
   1040   }
   1041 
   1042   Status = HiiUpdateForm (
   1043              mCallbackInfo->RegisteredHandle, // HII handle
   1044              &gIScsiConfigGuid,               // Formset GUID
   1045              FORMID_MAC_FORM,                 // Form ID
   1046              StartOpCodeHandle,               // Label for where to insert opcodes
   1047              EndOpCodeHandle                  // Replace data
   1048              );
   1049 
   1050 Exit:
   1051   HiiFreeOpCodeHandle (StartOpCodeHandle);
   1052   HiiFreeOpCodeHandle (EndOpCodeHandle);
   1053 
   1054   return Status;
   1055 }
   1056 
   1057 
   1058 /**
   1059   Update the MAIN form to display the configured attempts.
   1060 
   1061 **/
   1062 VOID
   1063 IScsiConfigUpdateAttempt (
   1064   VOID
   1065   )
   1066 {
   1067   CHAR16                        AttemptName[ATTEMPT_NAME_MAX_SIZE];
   1068   LIST_ENTRY                    *Entry;
   1069   ISCSI_ATTEMPT_CONFIG_NVDATA   *AttemptConfigData;
   1070   VOID                          *StartOpCodeHandle;
   1071   EFI_IFR_GUID_LABEL            *StartLabel;
   1072   VOID                          *EndOpCodeHandle;
   1073   EFI_IFR_GUID_LABEL            *EndLabel;
   1074   EFI_STATUS                    Status;
   1075 
   1076   Status = IScsiCreateOpCode (
   1077              ATTEMPT_ENTRY_LABEL,
   1078              &StartOpCodeHandle,
   1079              &StartLabel,
   1080              &EndOpCodeHandle,
   1081              &EndLabel
   1082              );
   1083   if (EFI_ERROR (Status)) {
   1084     return ;
   1085   }
   1086 
   1087   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
   1088     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
   1089 
   1090     AsciiStrToUnicodeStr (AttemptConfigData->AttemptName, AttemptName);
   1091     UnicodeSPrint (mPrivate->PortString, (UINTN) 128, L"Attempt %s", AttemptName);
   1092     AttemptConfigData->AttemptTitleToken = HiiSetString (
   1093                                              mCallbackInfo->RegisteredHandle,
   1094                                              0,
   1095                                              mPrivate->PortString,
   1096                                              NULL
   1097                                              );
   1098     if (AttemptConfigData->AttemptTitleToken == 0) {
   1099       return ;
   1100     }
   1101 
   1102     HiiCreateGotoOpCode (
   1103       StartOpCodeHandle,                         // Container for dynamic created opcodes
   1104       FORMID_ATTEMPT_FORM,                       // Form ID
   1105       AttemptConfigData->AttemptTitleToken,      // Prompt text
   1106       AttemptConfigData->AttemptTitleHelpToken,  // Help text
   1107       EFI_IFR_FLAG_CALLBACK,                     // Question flag
   1108       (UINT16) (KEY_ATTEMPT_ENTRY_BASE + AttemptConfigData->AttemptConfigIndex)   // Question ID
   1109       );
   1110   }
   1111 
   1112   HiiUpdateForm (
   1113     mCallbackInfo->RegisteredHandle, // HII handle
   1114     &gIScsiConfigGuid,               // Formset GUID
   1115     FORMID_MAIN_FORM,                // Form ID
   1116     StartOpCodeHandle,               // Label for where to insert opcodes
   1117     EndOpCodeHandle                  // Replace data
   1118   );
   1119 
   1120   HiiFreeOpCodeHandle (StartOpCodeHandle);
   1121   HiiFreeOpCodeHandle (EndOpCodeHandle);
   1122 }
   1123 
   1124 
   1125 /**
   1126   Callback function when user presses "Commit Changes and Exit" in Delete Attempts.
   1127 
   1128   @param[in]  IfrNvData          The IFR NV data.
   1129 
   1130   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
   1131   @retval EFI_SUCCESS            The operation is completed successfully.
   1132   @retval EFI_ABOTRED            This operation is aborted cause of error
   1133                                  configuration.
   1134   @retval EFI_OUT_OF_RESOURCES   Fail to finish the operation due to lack of
   1135                                  resources.
   1136 
   1137 **/
   1138 EFI_STATUS
   1139 IScsiConfigDeleteAttempts (
   1140   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
   1141   )
   1142 {
   1143   EFI_STATUS                  Status;
   1144   UINTN                       Index;
   1145   UINTN                       NewIndex;
   1146   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   1147   UINT8                       *AttemptConfigOrder;
   1148   UINTN                       AttemptConfigOrderSize;
   1149   UINT8                       *AttemptNewOrder;
   1150   UINT32                      Attribute;
   1151   UINTN                       Total;
   1152   UINTN                       NewTotal;
   1153   LIST_ENTRY                  *Entry;
   1154   LIST_ENTRY                  *NextEntry;
   1155   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
   1156 
   1157   AttemptConfigOrder = IScsiGetVariableAndSize (
   1158                          L"AttemptOrder",
   1159                          &gIScsiConfigGuid,
   1160                          &AttemptConfigOrderSize
   1161                          );
   1162   if ((AttemptConfigOrder == NULL) || (AttemptConfigOrderSize == 0)) {
   1163     return EFI_NOT_FOUND;
   1164   }
   1165 
   1166   AttemptNewOrder = AllocateZeroPool (AttemptConfigOrderSize);
   1167   if (AttemptNewOrder == NULL) {
   1168     Status = EFI_OUT_OF_RESOURCES;
   1169     goto Error;
   1170   }
   1171 
   1172   Total    = AttemptConfigOrderSize / sizeof (UINT8);
   1173   NewTotal = Total;
   1174   Index    = 0;
   1175 
   1176   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
   1177     if (IfrNvData->DeleteAttemptList[Index] == 0) {
   1178       Index++;
   1179       continue;
   1180     }
   1181 
   1182     //
   1183     // Delete the attempt.
   1184     //
   1185 
   1186     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
   1187     if (AttemptConfigData == NULL) {
   1188       Status = EFI_NOT_FOUND;
   1189       goto Error;
   1190     }
   1191 
   1192     //
   1193     // Remove this attempt from UI configured attempt list.
   1194     //
   1195     RemoveEntryList (&AttemptConfigData->Link);
   1196     mPrivate->AttemptCount--;
   1197 
   1198     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
   1199       if (mPrivate->MpioCount < 1) {
   1200         Status = EFI_ABORTED;
   1201         goto Error;
   1202       }
   1203 
   1204       //
   1205       // No more attempt is enabled for MPIO. Transit the iSCSI mode to single path.
   1206       //
   1207       if (--mPrivate->MpioCount == 0) {
   1208         mPrivate->EnableMpio = FALSE;
   1209       }
   1210     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
   1211       if (mPrivate->SinglePathCount < 1) {
   1212         Status = EFI_ABORTED;
   1213         goto Error;
   1214       }
   1215 
   1216       mPrivate->SinglePathCount--;
   1217     }
   1218 
   1219     AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
   1220 
   1221     UnicodeSPrint (
   1222       mPrivate->PortString,
   1223       (UINTN) 128,
   1224       L"%s%d",
   1225       MacString,
   1226       (UINTN) AttemptConfigData->AttemptConfigIndex
   1227       );
   1228 
   1229     gRT->SetVariable (
   1230            mPrivate->PortString,
   1231            &gEfiIScsiInitiatorNameProtocolGuid,
   1232            0,
   1233            0,
   1234            NULL
   1235            );
   1236 
   1237     //
   1238     // Mark the attempt order in NVR to be deleted - 0.
   1239     //
   1240     for (NewIndex = 0; NewIndex < Total; NewIndex++) {
   1241       if (AttemptConfigOrder[NewIndex] == AttemptConfigData->AttemptConfigIndex) {
   1242         AttemptConfigOrder[NewIndex] = 0;
   1243         break;
   1244       }
   1245     }
   1246 
   1247     NewTotal--;
   1248     FreePool (AttemptConfigData);
   1249 
   1250     //
   1251     // Check next Attempt.
   1252     //
   1253     Index++;
   1254   }
   1255 
   1256   //
   1257   // Construct AttemptNewOrder.
   1258   //
   1259   for (Index = 0, NewIndex = 0; Index < Total; Index++) {
   1260     if (AttemptConfigOrder[Index] != 0) {
   1261       AttemptNewOrder[NewIndex] = AttemptConfigOrder[Index];
   1262       NewIndex++;
   1263     }
   1264   }
   1265 
   1266   Attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE;
   1267 
   1268   //
   1269   // Update AttemptOrder in NVR.
   1270   //
   1271   Status = gRT->SetVariable (
   1272                   L"AttemptOrder",
   1273                   &gIScsiConfigGuid,
   1274                   Attribute,
   1275                   NewTotal * sizeof (UINT8),
   1276                   AttemptNewOrder
   1277                   );
   1278 
   1279 Error:
   1280   if (AttemptConfigOrder != NULL) {
   1281     FreePool (AttemptConfigOrder);
   1282   }
   1283 
   1284   if (AttemptNewOrder != NULL) {
   1285     FreePool (AttemptNewOrder);
   1286   }
   1287 
   1288   return Status;
   1289 }
   1290 
   1291 
   1292 /**
   1293   Callback function when user presses "Delete Attempts".
   1294 
   1295   @param[in]  IfrNvData          The IFR nv data.
   1296 
   1297   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
   1298   @retval EFI_BUFFER_TOO_SMALL   The buffer in UpdateData is too small.
   1299   @retval EFI_SUCCESS            The operation is completed successfully.
   1300 
   1301 **/
   1302 EFI_STATUS
   1303 IScsiConfigDisplayDeleteAttempts (
   1304   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
   1305   )
   1306 {
   1307 
   1308   UINT8                       *AttemptConfigOrder;
   1309   UINTN                       AttemptConfigOrderSize;
   1310   LIST_ENTRY                  *Entry;
   1311   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   1312   UINT8                       Index;
   1313   VOID                        *StartOpCodeHandle;
   1314   EFI_IFR_GUID_LABEL          *StartLabel;
   1315   VOID                        *EndOpCodeHandle;
   1316   EFI_IFR_GUID_LABEL          *EndLabel;
   1317   EFI_STATUS                  Status;
   1318 
   1319   Status = IScsiCreateOpCode (
   1320              DELETE_ENTRY_LABEL,
   1321              &StartOpCodeHandle,
   1322              &StartLabel,
   1323              &EndOpCodeHandle,
   1324              &EndLabel
   1325              );
   1326   if (EFI_ERROR (Status)) {
   1327     return Status;
   1328   }
   1329 
   1330   AttemptConfigOrder = IScsiGetVariableAndSize (
   1331                          L"AttemptOrder",
   1332                          &gIScsiConfigGuid,
   1333                          &AttemptConfigOrderSize
   1334                          );
   1335   if (AttemptConfigOrder != NULL) {
   1336     //
   1337     // Create the check box opcode to be deleted.
   1338     //
   1339     Index = 0;
   1340 
   1341     NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
   1342       AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
   1343       IfrNvData->DeleteAttemptList[Index] = 0x00;
   1344 
   1345       HiiCreateCheckBoxOpCode(
   1346         StartOpCodeHandle,
   1347         (EFI_QUESTION_ID) (ATTEMPT_DEL_QUESTION_ID + Index),
   1348         CONFIGURATION_VARSTORE_ID,
   1349         (UINT16) (ATTEMPT_DEL_VAR_OFFSET + Index),
   1350         AttemptConfigData->AttemptTitleToken,
   1351         AttemptConfigData->AttemptTitleHelpToken,
   1352         0,
   1353         0,
   1354         NULL
   1355         );
   1356 
   1357       Index++;
   1358 
   1359       if (Index == ISCSI_MAX_ATTEMPTS_NUM) {
   1360         break;
   1361       }
   1362     }
   1363 
   1364     FreePool (AttemptConfigOrder);
   1365   }
   1366 
   1367   Status = HiiUpdateForm (
   1368              mCallbackInfo->RegisteredHandle, // HII handle
   1369              &gIScsiConfigGuid,               // Formset GUID
   1370              FORMID_DELETE_FORM,              // Form ID
   1371              StartOpCodeHandle,               // Label for where to insert opcodes
   1372              EndOpCodeHandle                  // Replace data
   1373              );
   1374 
   1375   HiiFreeOpCodeHandle (StartOpCodeHandle);
   1376   HiiFreeOpCodeHandle (EndOpCodeHandle);
   1377 
   1378   return Status;
   1379 }
   1380 
   1381 
   1382 /**
   1383   Callback function when user presses "Change Attempt Order".
   1384 
   1385   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
   1386   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
   1387                                  operation.
   1388   @retval EFI_SUCCESS            The operation is completed successfully.
   1389 
   1390 **/
   1391 EFI_STATUS
   1392 IScsiConfigDisplayOrderAttempts (
   1393   VOID
   1394   )
   1395 {
   1396   EFI_STATUS                  Status;
   1397   UINT8                       Index;
   1398   LIST_ENTRY                  *Entry;
   1399   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   1400   VOID                        *StartOpCodeHandle;
   1401   EFI_IFR_GUID_LABEL          *StartLabel;
   1402   VOID                        *EndOpCodeHandle;
   1403   EFI_IFR_GUID_LABEL          *EndLabel;
   1404   VOID                        *OptionsOpCodeHandle;
   1405 
   1406   Status = IScsiCreateOpCode (
   1407              ORDER_ENTRY_LABEL,
   1408              &StartOpCodeHandle,
   1409              &StartLabel,
   1410              &EndOpCodeHandle,
   1411              &EndLabel
   1412              );
   1413   if (EFI_ERROR (Status)) {
   1414     return Status;
   1415   }
   1416   ASSERT (StartOpCodeHandle != NULL);
   1417 
   1418   OptionsOpCodeHandle = NULL;
   1419 
   1420   //
   1421   // If no attempt to be ordered, update the original form and exit.
   1422   //
   1423   if (mPrivate->AttemptCount == 0) {
   1424     goto Exit;
   1425   }
   1426 
   1427   //
   1428   // Create Option OpCode.
   1429   //
   1430   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
   1431   if (OptionsOpCodeHandle == NULL) {
   1432     Status = EFI_OUT_OF_RESOURCES;
   1433     goto Error;
   1434   }
   1435 
   1436   Index = 0;
   1437 
   1438   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
   1439     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
   1440     HiiCreateOneOfOptionOpCode (
   1441       OptionsOpCodeHandle,
   1442       AttemptConfigData->AttemptTitleToken,
   1443       0,
   1444       EFI_IFR_NUMERIC_SIZE_1,
   1445       AttemptConfigData->AttemptConfigIndex
   1446       );
   1447     Index++;
   1448   }
   1449 
   1450   ASSERT (Index == mPrivate->AttemptCount);
   1451 
   1452   HiiCreateOrderedListOpCode (
   1453     StartOpCodeHandle,                          // Container for dynamic created opcodes
   1454     DYNAMIC_ORDERED_LIST_QUESTION_ID,           // Question ID
   1455     CONFIGURATION_VARSTORE_ID,                  // VarStore ID
   1456     DYNAMIC_ORDERED_LIST_VAR_OFFSET,            // Offset in Buffer Storage
   1457     STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),     // Question prompt text
   1458     STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),     // Question help text
   1459     0,                                          // Question flag
   1460     EFI_IFR_UNIQUE_SET,                         // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET
   1461     EFI_IFR_NUMERIC_SIZE_1,                     // Data type of Question value
   1462     ISCSI_MAX_ATTEMPTS_NUM,                     // Maximum container
   1463     OptionsOpCodeHandle,                        // Option Opcode list
   1464     NULL                                        // Default Opcode is NULL
   1465     );
   1466 
   1467 Exit:
   1468   Status = HiiUpdateForm (
   1469              mCallbackInfo->RegisteredHandle, // HII handle
   1470              &gIScsiConfigGuid,               // Formset GUID
   1471              FORMID_ORDER_FORM,               // Form ID
   1472              StartOpCodeHandle,               // Label for where to insert opcodes
   1473              EndOpCodeHandle                  // Replace data
   1474              );
   1475 
   1476 Error:
   1477   HiiFreeOpCodeHandle (StartOpCodeHandle);
   1478   HiiFreeOpCodeHandle (EndOpCodeHandle);
   1479   if (OptionsOpCodeHandle != NULL) {
   1480     HiiFreeOpCodeHandle (OptionsOpCodeHandle);
   1481   }
   1482 
   1483   return Status;
   1484 }
   1485 
   1486 
   1487 /**
   1488   Callback function when user presses "Commit Changes and Exit" in Change Attempt Order.
   1489 
   1490   @param[in]  IfrNvData          The IFR nv data.
   1491 
   1492   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
   1493                                  operation.
   1494   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
   1495   @retval EFI_SUCCESS            The operation is completed successfully.
   1496 
   1497 **/
   1498 EFI_STATUS
   1499 IScsiConfigOrderAttempts (
   1500   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
   1501   )
   1502 {
   1503   EFI_STATUS                  Status;
   1504   UINTN                       Index;
   1505   UINTN                       Indexj;
   1506   UINT8                       AttemptConfigIndex;
   1507   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   1508   UINT8                       *AttemptConfigOrder;
   1509   UINT8                       *AttemptConfigOrderTmp;
   1510   UINTN                       AttemptConfigOrderSize;
   1511 
   1512   AttemptConfigOrder = IScsiGetVariableAndSize (
   1513                          L"AttemptOrder",
   1514                          &gIScsiConfigGuid,
   1515                          &AttemptConfigOrderSize
   1516                          );
   1517   if (AttemptConfigOrder == NULL) {
   1518     return EFI_NOT_FOUND;
   1519   }
   1520 
   1521   AttemptConfigOrderTmp = AllocateZeroPool (AttemptConfigOrderSize);
   1522   if (AttemptConfigOrderTmp == NULL) {
   1523     Status = EFI_OUT_OF_RESOURCES;
   1524     goto Exit;
   1525   }
   1526 
   1527   for (Index = 0; Index < ISCSI_MAX_ATTEMPTS_NUM; Index++) {
   1528     //
   1529     // The real content ends with 0.
   1530     //
   1531     if (IfrNvData->DynamicOrderedList[Index] == 0) {
   1532       break;
   1533     }
   1534 
   1535     AttemptConfigIndex = IfrNvData->DynamicOrderedList[Index];
   1536     AttemptConfigData  = IScsiConfigGetAttemptByConfigIndex (AttemptConfigIndex);
   1537     if (AttemptConfigData == NULL) {
   1538       Status = EFI_NOT_FOUND;
   1539       goto Exit;
   1540     }
   1541 
   1542     //
   1543     // Reorder the Attempt List.
   1544     //
   1545     RemoveEntryList (&AttemptConfigData->Link);
   1546     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
   1547 
   1548     AttemptConfigOrderTmp[Index] = AttemptConfigIndex;
   1549 
   1550     //
   1551     // Mark it to be deleted - 0.
   1552     //
   1553     for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {
   1554       if (AttemptConfigOrder[Indexj] == AttemptConfigIndex) {
   1555         AttemptConfigOrder[Indexj] = 0;
   1556         break;
   1557       }
   1558     }
   1559   }
   1560 
   1561   //
   1562   // Adjust the attempt order in NVR.
   1563   //
   1564   for (; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
   1565     for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {
   1566       if (AttemptConfigOrder[Indexj] != 0) {
   1567         AttemptConfigOrderTmp[Index] = AttemptConfigOrder[Indexj];
   1568         AttemptConfigOrder[Indexj]   = 0;
   1569         continue;
   1570       }
   1571     }
   1572   }
   1573 
   1574   Status = gRT->SetVariable (
   1575                   L"AttemptOrder",
   1576                   &gIScsiConfigGuid,
   1577                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1578                   AttemptConfigOrderSize,
   1579                   AttemptConfigOrderTmp
   1580                   );
   1581 
   1582 Exit:
   1583   if (AttemptConfigOrderTmp != NULL) {
   1584     FreePool (AttemptConfigOrderTmp);
   1585   }
   1586 
   1587   FreePool (AttemptConfigOrder);
   1588   return Status;
   1589 }
   1590 
   1591 
   1592 /**
   1593   Callback function when a user presses "Attempt *" or when a user selects a NIC to
   1594   create the new attempt.
   1595 
   1596   @param[in]  KeyValue           A unique value which is sent to the original
   1597                                  exporting driver so that it can identify the type
   1598                                  of data to expect.
   1599   @param[in]  IfrNvData          The IFR nv data.
   1600 
   1601   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
   1602                                  operation.
   1603   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
   1604   @retval EFI_SUCCESS            The operation is completed successfully.
   1605 
   1606 **/
   1607 EFI_STATUS
   1608 IScsiConfigProcessDefault (
   1609   IN  EFI_QUESTION_ID              KeyValue,
   1610   IN  ISCSI_CONFIG_IFR_NVDATA      *IfrNvData
   1611   )
   1612 {
   1613   BOOLEAN                     NewAttempt;
   1614   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   1615   ISCSI_SESSION_CONFIG_NVDATA *ConfigData;
   1616   UINT8                       CurrentAttemptConfigIndex;
   1617   ISCSI_NIC_INFO              *NicInfo;
   1618   UINT8                       NicIndex;
   1619   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
   1620   UINT8                       *AttemptConfigOrder;
   1621   UINTN                       AttemptConfigOrderSize;
   1622   UINTN                       TotalNumber;
   1623   UINTN                       Index;
   1624 
   1625   //
   1626   // Is User creating a new attempt?
   1627   //
   1628   NewAttempt = FALSE;
   1629 
   1630   if ((KeyValue >= KEY_MAC_ENTRY_BASE) &&
   1631       (KeyValue <= (UINT16) (mPrivate->MaxNic + KEY_MAC_ENTRY_BASE))) {
   1632     //
   1633     // User has pressed "Add an Attempt" and then selects a NIC.
   1634     //
   1635     NewAttempt = TRUE;
   1636   } else if ((KeyValue >= KEY_ATTEMPT_ENTRY_BASE) &&
   1637              (KeyValue < (ISCSI_MAX_ATTEMPTS_NUM + KEY_ATTEMPT_ENTRY_BASE))) {
   1638 
   1639     //
   1640     // User has pressed "Attempt *".
   1641     //
   1642     NewAttempt = FALSE;
   1643   } else {
   1644     //
   1645     // Don't process anything.
   1646     //
   1647     return EFI_SUCCESS;
   1648   }
   1649 
   1650   //
   1651   // Free any attempt that is previously created but not saved to system.
   1652   //
   1653   if (mPrivate->NewAttempt != NULL) {
   1654     FreePool (mPrivate->NewAttempt);
   1655     mPrivate->NewAttempt = NULL;
   1656   }
   1657 
   1658   if (NewAttempt) {
   1659     //
   1660     // Determine which NIC user has selected for the new created attempt.
   1661     //
   1662     NicIndex = (UINT8) (KeyValue - KEY_MAC_ENTRY_BASE);
   1663     NicInfo = IScsiGetNicInfoByIndex (NicIndex);
   1664     if (NicInfo == NULL) {
   1665       return EFI_NOT_FOUND;
   1666     }
   1667 
   1668     //
   1669     // Create new attempt.
   1670     //
   1671 
   1672     AttemptConfigData = AllocateZeroPool (sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA));
   1673     if (AttemptConfigData == NULL) {
   1674       return EFI_OUT_OF_RESOURCES;
   1675     }
   1676 
   1677     ConfigData                    = &AttemptConfigData->SessionConfigData;
   1678     ConfigData->TargetPort        = ISCSI_WELL_KNOWN_PORT;
   1679     ConfigData->ConnectTimeout    = CONNECT_DEFAULT_TIMEOUT;
   1680     ConfigData->ConnectRetryCount = CONNECT_MIN_RETRY;
   1681 
   1682     AttemptConfigData->AuthenticationType           = ISCSI_AUTH_TYPE_CHAP;
   1683     AttemptConfigData->AuthConfigData.CHAP.CHAPType = ISCSI_CHAP_UNI;
   1684 
   1685     //
   1686     // Get current order number for this attempt.
   1687     //
   1688     AttemptConfigOrder = IScsiGetVariableAndSize (
   1689                            L"AttemptOrder",
   1690                            &gIScsiConfigGuid,
   1691                            &AttemptConfigOrderSize
   1692                            );
   1693 
   1694     TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);
   1695 
   1696     if (AttemptConfigOrder == NULL) {
   1697       CurrentAttemptConfigIndex = 1;
   1698     } else {
   1699       //
   1700       // Get the max attempt config index.
   1701       //
   1702       CurrentAttemptConfigIndex = AttemptConfigOrder[0];
   1703       for (Index = 1; Index < TotalNumber; Index++) {
   1704         if (CurrentAttemptConfigIndex < AttemptConfigOrder[Index]) {
   1705           CurrentAttemptConfigIndex = AttemptConfigOrder[Index];
   1706         }
   1707       }
   1708 
   1709       CurrentAttemptConfigIndex++;
   1710     }
   1711 
   1712     TotalNumber++;
   1713 
   1714     //
   1715     // Record the mapping between attempt order and attempt's configdata.
   1716     //
   1717     AttemptConfigData->AttemptConfigIndex  = CurrentAttemptConfigIndex;
   1718 
   1719     if (AttemptConfigOrder != NULL) {
   1720       FreePool (AttemptConfigOrder);
   1721     }
   1722 
   1723     //
   1724     // Record the MAC info in Config Data.
   1725     //
   1726     IScsiMacAddrToStr (
   1727       &NicInfo->PermanentAddress,
   1728       NicInfo->HwAddressSize,
   1729       NicInfo->VlanId,
   1730       MacString
   1731       );
   1732 
   1733     UnicodeStrToAsciiStr (MacString, AttemptConfigData->MacString);
   1734     AttemptConfigData->NicIndex = NicIndex;
   1735 
   1736     //
   1737     // Generate OUI-format ISID based on MAC address.
   1738     //
   1739     CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6);
   1740     AttemptConfigData->SessionConfigData.IsId[0] =
   1741       (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F);
   1742 
   1743     //
   1744     // Add the help info for the new attempt.
   1745     //
   1746     UnicodeSPrint (
   1747       mPrivate->PortString,
   1748       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
   1749       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d",
   1750       MacString,
   1751       NicInfo->BusNumber,
   1752       NicInfo->DeviceNumber,
   1753       NicInfo->FunctionNumber
   1754       );
   1755 
   1756     AttemptConfigData->AttemptTitleHelpToken  = HiiSetString (
   1757                                                   mCallbackInfo->RegisteredHandle,
   1758                                                   0,
   1759                                                   mPrivate->PortString,
   1760                                                   NULL
   1761                                                   );
   1762     if (AttemptConfigData->AttemptTitleHelpToken == 0) {
   1763       FreePool (AttemptConfigData);
   1764       return EFI_INVALID_PARAMETER;
   1765     }
   1766 
   1767     //
   1768     // Set the attempt name to default.
   1769     //
   1770     UnicodeSPrint (
   1771       mPrivate->PortString,
   1772       (UINTN) 128,
   1773       L"%d",
   1774       (UINTN) AttemptConfigData->AttemptConfigIndex
   1775       );
   1776     UnicodeStrToAsciiStr (mPrivate->PortString, AttemptConfigData->AttemptName);
   1777 
   1778     //
   1779     // Save the created Attempt temporarily. If user does not save the attempt
   1780     // by press 'KEY_SAVE_ATTEMPT_CONFIG' later, iSCSI driver would know that
   1781     // and free resources.
   1782     //
   1783     mPrivate->NewAttempt = (VOID *) AttemptConfigData;
   1784 
   1785   } else {
   1786     //
   1787     // Determine which Attempt user has selected to configure.
   1788     // Get the attempt configuration data.
   1789     //
   1790     CurrentAttemptConfigIndex = (UINT8) (KeyValue - KEY_ATTEMPT_ENTRY_BASE);
   1791 
   1792     AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (CurrentAttemptConfigIndex);
   1793     if (AttemptConfigData == NULL) {
   1794       DEBUG ((DEBUG_ERROR, "Corresponding configuration data can not be retrieved!\n"));
   1795       return EFI_NOT_FOUND;
   1796     }
   1797   }
   1798 
   1799   //
   1800   // Clear the old IFR data to avoid sharing it with other attempts.
   1801   //
   1802   if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
   1803     ZeroMem (IfrNvData->CHAPName, sizeof (IfrNvData->CHAPName));
   1804     ZeroMem (IfrNvData->CHAPSecret, sizeof (IfrNvData->CHAPSecret));
   1805     ZeroMem (IfrNvData->ReverseCHAPName, sizeof (IfrNvData->ReverseCHAPName));
   1806     ZeroMem (IfrNvData->ReverseCHAPSecret, sizeof (IfrNvData->ReverseCHAPSecret));
   1807   }
   1808 
   1809   IScsiConvertAttemptConfigDataToIfrNvData (AttemptConfigData, IfrNvData);
   1810 
   1811   //
   1812   // Update current attempt to be a new created attempt or an existing attempt.
   1813   //
   1814   mCallbackInfo->Current = AttemptConfigData;
   1815 
   1816   return EFI_SUCCESS;
   1817 }
   1818 
   1819 
   1820 /**
   1821 
   1822   This function allows the caller to request the current
   1823   configuration for one or more named elements. The resulting
   1824   string is in <ConfigAltResp> format. Also, any and all alternative
   1825   configuration strings shall be appended to the end of the
   1826   current configuration string. If they are, they must appear
   1827   after the current configuration. They must contain the same
   1828   routing (GUID, NAME, PATH) as the current configuration string.
   1829   They must have an additional description indicating the type of
   1830   alternative configuration the string represents,
   1831   "ALTCFG=<StringToken>". That <StringToken> (when
   1832   converted from Hex UNICODE to binary) is a reference to a
   1833   string in the associated string pack.
   1834 
   1835   @param[in]  This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1836 
   1837   @param[in]  Request    A null-terminated Unicode string in
   1838                          <ConfigRequest> format. Note that this
   1839                          includes the routing information as well as
   1840                          the configurable name / value pairs. It is
   1841                          invalid for this string to be in
   1842                          <MultiConfigRequest> format.
   1843 
   1844   @param[out] Progress   On return, points to a character in the
   1845                          Request string. Points to the string's null
   1846                          terminator if request was successful. Points
   1847                          to the most recent "&" before the first
   1848                          failing name / value pair (or the beginning
   1849                          of the string if the failure is in the first
   1850                          name / value pair) if the request was not successful.
   1851 
   1852   @param[out] Results    A null-terminated Unicode string in
   1853                          <ConfigAltResp> format which has all values
   1854                          filled in for the names in the Request string.
   1855                          String to be allocated by the called function.
   1856 
   1857   @retval EFI_SUCCESS             The Results string is filled with the
   1858                                   values corresponding to all requested
   1859                                   names.
   1860 
   1861   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
   1862                                   parts of the results that must be
   1863                                   stored awaiting possible future
   1864                                   protocols.
   1865 
   1866   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL
   1867                                   for the Request parameter
   1868                                   would result in this type of
   1869                                   error. In this case, the
   1870                                   Progress parameter would be
   1871                                   set to NULL.
   1872 
   1873   @retval EFI_NOT_FOUND           Routing data doesn't match any
   1874                                   known driver. Progress set to the
   1875                                   first character in the routing header.
   1876                                   Note: There is no requirement that the
   1877                                   driver validate the routing data. It
   1878                                   must skip the <ConfigHdr> in order to
   1879                                   process the names.
   1880 
   1881   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
   1882                                   to most recent "&" before the
   1883                                   error or the beginning of the
   1884                                   string.
   1885 
   1886   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
   1887                                   to the & before the name in
   1888                                   question.
   1889 
   1890 **/
   1891 EFI_STATUS
   1892 EFIAPI
   1893 IScsiFormExtractConfig (
   1894   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1895   IN  CONST EFI_STRING                       Request,
   1896   OUT EFI_STRING                             *Progress,
   1897   OUT EFI_STRING                             *Results
   1898   )
   1899 {
   1900   EFI_STATUS                       Status;
   1901   CHAR8                            *InitiatorName;
   1902   UINTN                            BufferSize;
   1903   ISCSI_CONFIG_IFR_NVDATA          *IfrNvData;
   1904   ISCSI_FORM_CALLBACK_INFO         *Private;
   1905   EFI_STRING                       ConfigRequestHdr;
   1906   EFI_STRING                       ConfigRequest;
   1907   BOOLEAN                          AllocatedRequest;
   1908   UINTN                            Size;
   1909 
   1910   if (This == NULL || Progress == NULL || Results == NULL) {
   1911     return EFI_INVALID_PARAMETER;
   1912   }
   1913 
   1914   *Progress = Request;
   1915   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gIScsiConfigGuid, mVendorStorageName)) {
   1916     return EFI_NOT_FOUND;
   1917   }
   1918 
   1919   ConfigRequestHdr = NULL;
   1920   ConfigRequest    = NULL;
   1921   AllocatedRequest = FALSE;
   1922   Size             = 0;
   1923 
   1924   Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
   1925   IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
   1926   if (IfrNvData == NULL) {
   1927     return EFI_OUT_OF_RESOURCES;
   1928   }
   1929 
   1930   if (Private->Current != NULL) {
   1931     IScsiConvertAttemptConfigDataToIfrNvData (Private->Current, IfrNvData);
   1932   }
   1933 
   1934   BufferSize    = ISCSI_NAME_MAX_SIZE;
   1935   InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize);
   1936   if (InitiatorName == NULL) {
   1937     FreePool (IfrNvData);
   1938     return EFI_OUT_OF_RESOURCES;
   1939   }
   1940 
   1941   Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
   1942   if (EFI_ERROR (Status)) {
   1943     IfrNvData->InitiatorName[0] = L'\0';
   1944   } else {
   1945     AsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);
   1946   }
   1947 
   1948   //
   1949   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
   1950   //
   1951   BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
   1952   ConfigRequest = Request;
   1953   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
   1954     //
   1955     // Request has no request element, construct full request string.
   1956     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
   1957     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
   1958     //
   1959     ConfigRequestHdr = HiiConstructConfigHdr (&gIScsiConfigGuid, mVendorStorageName, Private->DriverHandle);
   1960     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
   1961     ConfigRequest = AllocateZeroPool (Size);
   1962     ASSERT (ConfigRequest != NULL);
   1963     AllocatedRequest = TRUE;
   1964     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
   1965     FreePool (ConfigRequestHdr);
   1966   }
   1967 
   1968   Status = gHiiConfigRouting->BlockToConfig (
   1969                                 gHiiConfigRouting,
   1970                                 ConfigRequest,
   1971                                 (UINT8 *) IfrNvData,
   1972                                 BufferSize,
   1973                                 Results,
   1974                                 Progress
   1975                                 );
   1976   FreePool (IfrNvData);
   1977   FreePool (InitiatorName);
   1978 
   1979   //
   1980   // Free the allocated config request string.
   1981   //
   1982   if (AllocatedRequest) {
   1983     FreePool (ConfigRequest);
   1984     ConfigRequest = NULL;
   1985   }
   1986   //
   1987   // Set Progress string to the original request string.
   1988   //
   1989   if (Request == NULL) {
   1990     *Progress = NULL;
   1991   } else if (StrStr (Request, L"OFFSET") == NULL) {
   1992     *Progress = Request + StrLen (Request);
   1993   }
   1994 
   1995   return Status;
   1996 }
   1997 
   1998 
   1999 /**
   2000 
   2001   This function applies changes in a driver's configuration.
   2002   Input is a Configuration, which has the routing data for this
   2003   driver followed by name / value configuration pairs. The driver
   2004   must apply those pairs to its configurable storage. If the
   2005   driver's configuration is stored in a linear block of data
   2006   and the driver's name / value pairs are in <BlockConfig>
   2007   format, it may use the ConfigToBlock helper function (above) to
   2008   simplify the job.
   2009 
   2010   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   2011 
   2012   @param[in]  Configuration  A null-terminated Unicode string in
   2013                              <ConfigString> format.
   2014 
   2015   @param[out] Progress       A pointer to a string filled in with the
   2016                              offset of the most recent '&' before the
   2017                              first failing name / value pair (or the
   2018                              beginning of the string if the failure
   2019                              is in the first name / value pair) or
   2020                              the terminating NULL if all was
   2021                              successful.
   2022 
   2023   @retval EFI_SUCCESS             The results have been distributed or are
   2024                                   awaiting distribution.
   2025 
   2026   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
   2027                                   parts of the results that must be
   2028                                   stored awaiting possible future
   2029                                   protocols.
   2030 
   2031   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
   2032                                   Results parameter would result
   2033                                   in this type of error.
   2034 
   2035   @retval EFI_NOT_FOUND           Target for the specified routing data
   2036                                   was not found.
   2037 
   2038 **/
   2039 EFI_STATUS
   2040 EFIAPI
   2041 IScsiFormRouteConfig (
   2042   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   2043   IN  CONST EFI_STRING                       Configuration,
   2044   OUT EFI_STRING                             *Progress
   2045   )
   2046 {
   2047   if (This == NULL || Configuration == NULL || Progress == NULL) {
   2048     return EFI_INVALID_PARAMETER;
   2049   }
   2050 
   2051   //
   2052   // Check routing data in <ConfigHdr>.
   2053   // Note: if only one Storage is used, then this checking could be skipped.
   2054   //
   2055   if (!HiiIsConfigHdrMatch (Configuration, &gIScsiConfigGuid, mVendorStorageName)) {
   2056     *Progress = Configuration;
   2057     return EFI_NOT_FOUND;
   2058   }
   2059 
   2060   *Progress = Configuration + StrLen (Configuration);
   2061   return EFI_SUCCESS;
   2062 }
   2063 
   2064 
   2065 /**
   2066 
   2067   This function is called to provide results data to the driver.
   2068   This data consists of a unique key that is used to identify
   2069   which data is either being passed back or being asked for.
   2070 
   2071   @param[in]       This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   2072   @param[in]       Action        Specifies the type of action taken by the browser.
   2073   @param[in]       QuestionId    A unique value which is sent to the original
   2074                                  exporting driver so that it can identify the type
   2075                                  of data to expect. The format of the data tends to
   2076                                  vary based on the opcode that generated the callback.
   2077   @param[in]       Type          The type of value for the question.
   2078   @param[in, out]  Value         A pointer to the data being sent to the original
   2079                                  exporting driver.
   2080   @param[out]      ActionRequest On return, points to the action requested by the
   2081                                  callback function.
   2082 
   2083   @retval EFI_SUCCESS            The callback successfully handled the action.
   2084   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
   2085                                  variable and its data.
   2086   @retval EFI_DEVICE_ERROR       The variable could not be saved.
   2087   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
   2088                                  callback.
   2089 **/
   2090 EFI_STATUS
   2091 EFIAPI
   2092 IScsiFormCallback (
   2093   IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   2094   IN        EFI_BROWSER_ACTION               Action,
   2095   IN        EFI_QUESTION_ID                  QuestionId,
   2096   IN        UINT8                            Type,
   2097   IN OUT    EFI_IFR_TYPE_VALUE               *Value,
   2098   OUT       EFI_BROWSER_ACTION_REQUEST       *ActionRequest
   2099   )
   2100 {
   2101   ISCSI_FORM_CALLBACK_INFO    *Private;
   2102   UINTN                       BufferSize;
   2103   CHAR8                       *IScsiName;
   2104   CHAR8                       IpString[IP_STR_MAX_SIZE];
   2105   CHAR8                       LunString[ISCSI_LUN_STR_MAX_LEN];
   2106   UINT64                      Lun;
   2107   EFI_IP_ADDRESS              HostIp;
   2108   EFI_IP_ADDRESS              SubnetMask;
   2109   EFI_IP_ADDRESS              Gateway;
   2110   ISCSI_CONFIG_IFR_NVDATA     *IfrNvData;
   2111   ISCSI_CONFIG_IFR_NVDATA     OldIfrNvData;
   2112   EFI_STATUS                  Status;
   2113   CHAR16                      AttemptName[ATTEMPT_NAME_SIZE + 4];
   2114   EFI_INPUT_KEY               Key;
   2115 
   2116   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) {
   2117     //
   2118     // Do nothing for UEFI OPEN/CLOSE Action
   2119     //
   2120     return EFI_SUCCESS;
   2121   }
   2122 
   2123   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
   2124     //
   2125     // All other type return unsupported.
   2126     //
   2127     return EFI_UNSUPPORTED;
   2128   }
   2129 
   2130   if ((Value == NULL) || (ActionRequest == NULL)) {
   2131     return EFI_INVALID_PARAMETER;
   2132   }
   2133 
   2134   Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
   2135 
   2136   //
   2137   // Retrieve uncommitted data from Browser
   2138   //
   2139 
   2140   BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
   2141   IfrNvData = AllocateZeroPool (BufferSize);
   2142   if (IfrNvData == NULL) {
   2143     return EFI_OUT_OF_RESOURCES;
   2144   }
   2145 
   2146   IScsiName = (CHAR8 *) AllocateZeroPool (ISCSI_NAME_MAX_SIZE);
   2147   if (IScsiName == NULL) {
   2148     FreePool (IfrNvData);
   2149     return EFI_OUT_OF_RESOURCES;
   2150   }
   2151 
   2152   Status = EFI_SUCCESS;
   2153 
   2154   ZeroMem (&OldIfrNvData, BufferSize);
   2155 
   2156   HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);
   2157 
   2158   CopyMem (&OldIfrNvData, IfrNvData, BufferSize);
   2159 
   2160   if (Action == EFI_BROWSER_ACTION_CHANGING) {
   2161     switch (QuestionId) {
   2162     case KEY_ADD_ATTEMPT:
   2163       //
   2164       // Check whether iSCSI initiator name is configured already.
   2165       //
   2166       mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
   2167       Status = gIScsiInitiatorName.Get (
   2168                                      &gIScsiInitiatorName,
   2169                                      &mPrivate->InitiatorNameLength,
   2170                                      mPrivate->InitiatorName
   2171                                      );
   2172       if (EFI_ERROR (Status)) {
   2173         CreatePopUp (
   2174           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2175           &Key,
   2176           L"Error: please configure iSCSI initiator name first!",
   2177           NULL
   2178           );
   2179         break;
   2180       }
   2181 
   2182       Status = IScsiConfigAddAttempt ();
   2183       break;
   2184 
   2185     case KEY_DELETE_ATTEMPT:
   2186       CopyMem (
   2187         OldIfrNvData.DeleteAttemptList,
   2188         IfrNvData->DeleteAttemptList,
   2189         sizeof (IfrNvData->DeleteAttemptList)
   2190         );
   2191       Status = IScsiConfigDisplayDeleteAttempts (IfrNvData);
   2192       break;
   2193 
   2194     case KEY_ORDER_ATTEMPT_CONFIG:
   2195       //
   2196       // Order the attempt according to user input.
   2197       //
   2198       CopyMem (
   2199         OldIfrNvData.DynamicOrderedList,
   2200         IfrNvData->DynamicOrderedList,
   2201         sizeof (IfrNvData->DynamicOrderedList)
   2202         );
   2203       IScsiConfigDisplayOrderAttempts ();
   2204       break;
   2205 
   2206     default:
   2207       Status = IScsiConfigProcessDefault (QuestionId, IfrNvData);
   2208       break;
   2209     }
   2210   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
   2211     switch (QuestionId) {
   2212     case KEY_INITIATOR_NAME:
   2213       UnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);
   2214       BufferSize  = AsciiStrSize (IScsiName);
   2215 
   2216       Status      = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);
   2217       if (EFI_ERROR (Status)) {
   2218         CreatePopUp (
   2219           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2220           &Key,
   2221           L"Invalid iSCSI Name!",
   2222           NULL
   2223           );
   2224       }
   2225 
   2226       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
   2227       break;
   2228     case KEY_ATTEMPT_NAME:
   2229       if (StrLen (IfrNvData->AttemptName) > ATTEMPT_NAME_SIZE) {
   2230         CopyMem (AttemptName, IfrNvData->AttemptName, ATTEMPT_NAME_SIZE * sizeof (CHAR16));
   2231         CopyMem (&AttemptName[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));
   2232       } else {
   2233         CopyMem (
   2234           AttemptName,
   2235           IfrNvData->AttemptName,
   2236           (StrLen (IfrNvData->AttemptName) + 1) * sizeof (CHAR16)
   2237           );
   2238       }
   2239 
   2240       UnicodeStrToAsciiStr (IfrNvData->AttemptName, Private->Current->AttemptName);
   2241 
   2242       IScsiConfigUpdateAttempt ();
   2243 
   2244       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
   2245       break;
   2246 
   2247     case KEY_SAVE_ATTEMPT_CONFIG:
   2248       Status = IScsiConvertIfrNvDataToAttemptConfigData (IfrNvData, Private->Current);
   2249       if (EFI_ERROR (Status)) {
   2250         break;
   2251       }
   2252 
   2253       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
   2254       break;
   2255 
   2256     case KEY_SAVE_ORDER_CHANGES:
   2257       //
   2258       // Sync the Attempt Order to NVR.
   2259       //
   2260       Status = IScsiConfigOrderAttempts (IfrNvData);
   2261       if (EFI_ERROR (Status)) {
   2262         break;
   2263       }
   2264 
   2265       IScsiConfigUpdateAttempt ();
   2266       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   2267       break;
   2268 
   2269     case KEY_IGNORE_ORDER_CHANGES:
   2270       CopyMem (
   2271         IfrNvData->DynamicOrderedList,
   2272         OldIfrNvData.DynamicOrderedList,
   2273         sizeof (IfrNvData->DynamicOrderedList)
   2274         );
   2275       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   2276       break;
   2277 
   2278     case KEY_SAVE_DELETE_ATTEMPT:
   2279       //
   2280       // Delete the Attempt Order from NVR
   2281       //
   2282       Status = IScsiConfigDeleteAttempts (IfrNvData);
   2283       if (EFI_ERROR (Status)) {
   2284         break;
   2285       }
   2286 
   2287       IScsiConfigUpdateAttempt ();
   2288       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   2289       break;
   2290 
   2291     case KEY_IGNORE_DELETE_ATTEMPT:
   2292       CopyMem (
   2293         IfrNvData->DeleteAttemptList,
   2294         OldIfrNvData.DeleteAttemptList,
   2295         sizeof (IfrNvData->DeleteAttemptList)
   2296         );
   2297       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   2298       break;
   2299 
   2300     case KEY_IP_MODE:
   2301       switch (Value->u8) {
   2302       case IP_MODE_IP6:
   2303         ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
   2304         IScsiIpToStr (&Private->Current->SessionConfigData.TargetIp, TRUE, IfrNvData->TargetIp);
   2305         Private->Current->AutoConfigureMode = 0;
   2306         break;
   2307 
   2308       case IP_MODE_IP4:
   2309         ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
   2310         IScsiIpToStr (&Private->Current->SessionConfigData.TargetIp, FALSE, IfrNvData->TargetIp);
   2311         Private->Current->AutoConfigureMode = 0;
   2312 
   2313         break;
   2314       }
   2315 
   2316       break;
   2317 
   2318     case KEY_LOCAL_IP:
   2319       Status = NetLibStrToIp4 (IfrNvData->LocalIp, &HostIp.v4);
   2320       if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
   2321         CreatePopUp (
   2322           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2323           &Key,
   2324           L"Invalid IP address!",
   2325           NULL
   2326           );
   2327 
   2328         Status = EFI_INVALID_PARAMETER;
   2329       } else {
   2330         CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
   2331       }
   2332 
   2333       break;
   2334 
   2335     case KEY_SUBNET_MASK:
   2336       Status = NetLibStrToIp4 (IfrNvData->SubnetMask, &SubnetMask.v4);
   2337       if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
   2338         CreatePopUp (
   2339           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2340           &Key,
   2341           L"Invalid Subnet Mask!",
   2342           NULL
   2343           );
   2344 
   2345         Status = EFI_INVALID_PARAMETER;
   2346       } else {
   2347         CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
   2348       }
   2349 
   2350       break;
   2351 
   2352     case KEY_GATE_WAY:
   2353       Status = NetLibStrToIp4 (IfrNvData->Gateway, &Gateway.v4);
   2354       if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {
   2355         CreatePopUp (
   2356           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2357           &Key,
   2358           L"Invalid Gateway!",
   2359           NULL
   2360           );
   2361         Status = EFI_INVALID_PARAMETER;
   2362       } else {
   2363         CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
   2364       }
   2365 
   2366       break;
   2367 
   2368     case KEY_TARGET_IP:
   2369       UnicodeStrToAsciiStr (IfrNvData->TargetIp, IpString);
   2370       Status = IScsiAsciiStrToIp (IpString, IfrNvData->IpMode, &HostIp);
   2371       if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, IfrNvData->IpMode)) {
   2372         CreatePopUp (
   2373           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2374           &Key,
   2375           L"Invalid IP address!",
   2376           NULL
   2377           );
   2378         Status = EFI_INVALID_PARAMETER;
   2379       } else {
   2380         CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp));
   2381       }
   2382 
   2383       break;
   2384 
   2385     case KEY_TARGET_NAME:
   2386       UnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);
   2387       Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
   2388       if (EFI_ERROR (Status)) {
   2389         CreatePopUp (
   2390           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2391           &Key,
   2392           L"Invalid iSCSI Name!",
   2393           NULL
   2394           );
   2395       } else {
   2396         AsciiStrCpyS (Private->Current->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName);
   2397       }
   2398 
   2399       break;
   2400 
   2401     case KEY_DHCP_ENABLE:
   2402       if (IfrNvData->InitiatorInfoFromDhcp == 0) {
   2403         IfrNvData->TargetInfoFromDhcp = 0;
   2404       }
   2405 
   2406       break;
   2407 
   2408     case KEY_BOOT_LUN:
   2409       UnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);
   2410       Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
   2411       if (EFI_ERROR (Status)) {
   2412         CreatePopUp (
   2413           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   2414           &Key,
   2415           L"Invalid LUN string!",
   2416           NULL
   2417           );
   2418       } else {
   2419         CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));
   2420       }
   2421 
   2422       break;
   2423 
   2424     case KEY_AUTH_TYPE:
   2425       switch (Value->u8) {
   2426       case ISCSI_AUTH_TYPE_CHAP:
   2427         IfrNvData->CHAPType = ISCSI_CHAP_UNI;
   2428         break;
   2429       default:
   2430         break;
   2431       }
   2432 
   2433       break;
   2434 
   2435     case KEY_CHAP_NAME:
   2436       UnicodeStrToAsciiStr (
   2437         IfrNvData->CHAPName,
   2438         Private->Current->AuthConfigData.CHAP.CHAPName
   2439         );
   2440       break;
   2441 
   2442     case KEY_CHAP_SECRET:
   2443       UnicodeStrToAsciiStr (
   2444         IfrNvData->CHAPSecret,
   2445         Private->Current->AuthConfigData.CHAP.CHAPSecret
   2446         );
   2447       break;
   2448 
   2449     case KEY_REVERSE_CHAP_NAME:
   2450       UnicodeStrToAsciiStr (
   2451         IfrNvData->ReverseCHAPName,
   2452         Private->Current->AuthConfigData.CHAP.ReverseCHAPName
   2453         );
   2454       break;
   2455 
   2456     case KEY_REVERSE_CHAP_SECRET:
   2457       UnicodeStrToAsciiStr (
   2458         IfrNvData->ReverseCHAPSecret,
   2459         Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret
   2460         );
   2461       break;
   2462 
   2463     case KEY_CONFIG_ISID:
   2464       IScsiParseIsIdFromString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
   2465       IScsiConvertIsIdToString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
   2466 
   2467       break;
   2468 
   2469     default:
   2470       break;
   2471     }
   2472   }
   2473 
   2474   if (!EFI_ERROR (Status)) {
   2475     //
   2476     // Pass changed uncommitted data back to Form Browser.
   2477     //
   2478     BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
   2479     HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
   2480   }
   2481 
   2482   FreePool (IfrNvData);
   2483   FreePool (IScsiName);
   2484 
   2485   return Status;
   2486 }
   2487 
   2488 
   2489 /**
   2490   Initialize the iSCSI configuration form.
   2491 
   2492   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
   2493 
   2494   @retval EFI_SUCCESS             The iSCSI configuration form is initialized.
   2495   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
   2496 
   2497 **/
   2498 EFI_STATUS
   2499 IScsiConfigFormInit (
   2500   IN EFI_HANDLE  DriverBindingHandle
   2501   )
   2502 {
   2503   EFI_STATUS                  Status;
   2504   ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;
   2505 
   2506   CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));
   2507   if (CallbackInfo == NULL) {
   2508     return EFI_OUT_OF_RESOURCES;
   2509   }
   2510 
   2511   CallbackInfo->Signature   = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
   2512   CallbackInfo->Current     = NULL;
   2513 
   2514   CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
   2515   CallbackInfo->ConfigAccess.RouteConfig   = IScsiFormRouteConfig;
   2516   CallbackInfo->ConfigAccess.Callback      = IScsiFormCallback;
   2517 
   2518   //
   2519   // Install Device Path Protocol and Config Access protocol to driver handle.
   2520   //
   2521   Status = gBS->InstallMultipleProtocolInterfaces (
   2522                   &CallbackInfo->DriverHandle,
   2523                   &gEfiDevicePathProtocolGuid,
   2524                   &mIScsiHiiVendorDevicePath,
   2525                   &gEfiHiiConfigAccessProtocolGuid,
   2526                   &CallbackInfo->ConfigAccess,
   2527                   NULL
   2528                   );
   2529   ASSERT_EFI_ERROR (Status);
   2530 
   2531   //
   2532   // Publish our HII data.
   2533   //
   2534   CallbackInfo->RegisteredHandle = HiiAddPackages (
   2535                                      &gIScsiConfigGuid,
   2536                                      CallbackInfo->DriverHandle,
   2537                                      IScsiDxeStrings,
   2538                                      IScsiConfigVfrBin,
   2539                                      NULL
   2540                                      );
   2541   if (CallbackInfo->RegisteredHandle == NULL) {
   2542     gBS->UninstallMultipleProtocolInterfaces (
   2543            &CallbackInfo->DriverHandle,
   2544            &gEfiDevicePathProtocolGuid,
   2545            &mIScsiHiiVendorDevicePath,
   2546            &gEfiHiiConfigAccessProtocolGuid,
   2547            &CallbackInfo->ConfigAccess,
   2548            NULL
   2549            );
   2550     FreePool(CallbackInfo);
   2551     return EFI_OUT_OF_RESOURCES;
   2552   }
   2553 
   2554   mCallbackInfo = CallbackInfo;
   2555 
   2556   return EFI_SUCCESS;
   2557 }
   2558 
   2559 
   2560 /**
   2561   Unload the iSCSI configuration form, this includes: delete all the iSCSI
   2562   configuration entries, uninstall the form callback protocol, and
   2563   free the resources used.
   2564 
   2565   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
   2566 
   2567   @retval EFI_SUCCESS             The iSCSI configuration form is unloaded.
   2568   @retval Others                  Failed to unload the form.
   2569 
   2570 **/
   2571 EFI_STATUS
   2572 IScsiConfigFormUnload (
   2573   IN EFI_HANDLE  DriverBindingHandle
   2574   )
   2575 {
   2576   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
   2577   ISCSI_NIC_INFO              *NicInfo;
   2578   LIST_ENTRY                  *Entry;
   2579   EFI_STATUS                  Status;
   2580 
   2581   while (!IsListEmpty (&mPrivate->AttemptConfigs)) {
   2582     Entry = NetListRemoveHead (&mPrivate->AttemptConfigs);
   2583     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
   2584     FreePool (AttemptConfigData);
   2585     mPrivate->AttemptCount--;
   2586   }
   2587 
   2588   ASSERT (mPrivate->AttemptCount == 0);
   2589 
   2590   while (!IsListEmpty (&mPrivate->NicInfoList)) {
   2591     Entry = NetListRemoveHead (&mPrivate->NicInfoList);
   2592     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
   2593     FreePool (NicInfo);
   2594     mPrivate->NicCount--;
   2595   }
   2596 
   2597   ASSERT (mPrivate->NicCount == 0);
   2598 
   2599   //
   2600   // Free attempt is created but not saved to system.
   2601   //
   2602   if (mPrivate->NewAttempt != NULL) {
   2603     FreePool (mPrivate->NewAttempt);
   2604   }
   2605 
   2606   FreePool (mPrivate);
   2607   mPrivate = NULL;
   2608 
   2609   //
   2610   // Remove HII package list.
   2611   //
   2612   HiiRemovePackages (mCallbackInfo->RegisteredHandle);
   2613 
   2614   //
   2615   // Uninstall Device Path Protocol and Config Access protocol.
   2616   //
   2617   Status = gBS->UninstallMultipleProtocolInterfaces (
   2618                   mCallbackInfo->DriverHandle,
   2619                   &gEfiDevicePathProtocolGuid,
   2620                   &mIScsiHiiVendorDevicePath,
   2621                   &gEfiHiiConfigAccessProtocolGuid,
   2622                   &mCallbackInfo->ConfigAccess,
   2623                   NULL
   2624                   );
   2625 
   2626   FreePool (mCallbackInfo);
   2627 
   2628   return Status;
   2629 }
   2630