1 /** @file
2   Helper functions for configuring or getting the parameters relating to iSCSI.
3 
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "IScsiImpl.h"
10 
11 CHAR16          mVendorStorageName[]     = L"ISCSI_CONFIG_IFR_NVDATA";
12 ISCSI_FORM_CALLBACK_INFO  *mCallbackInfo = NULL;
13 
14 HII_VENDOR_DEVICE_PATH  mIScsiHiiVendorDevicePath = {
15   {
16     {
17       HARDWARE_DEVICE_PATH,
18       HW_VENDOR_DP,
19       {
20         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
21         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
22       }
23     },
24     ISCSI_CONFIG_GUID
25   },
26   {
27     END_DEVICE_PATH_TYPE,
28     END_ENTIRE_DEVICE_PATH_SUBTYPE,
29     {
30       (UINT8) (END_DEVICE_PATH_LENGTH),
31       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
32     }
33   }
34 };
35 
36 
37 /**
38   Convert the IP address into a dotted string.
39 
40   @param[in]  Ip        The IP address.
41   @param[in]  Ipv6Flag  Indicates whether the IP address is version 4 or version 6.
42   @param[out] Str       The formatted IP string.
43 
44 **/
45 VOID
IScsiIpToStr(IN EFI_IP_ADDRESS * Ip,IN BOOLEAN Ipv6Flag,OUT CHAR16 * Str)46 IScsiIpToStr (
47   IN  EFI_IP_ADDRESS    *Ip,
48   IN  BOOLEAN           Ipv6Flag,
49   OUT CHAR16            *Str
50   )
51 {
52   EFI_IPv4_ADDRESS      *Ip4;
53   EFI_IPv6_ADDRESS      *Ip6;
54   UINTN                 Index;
55   BOOLEAN               Short;
56   UINTN                 Number;
57   CHAR16                FormatString[8];
58 
59   if (!Ipv6Flag) {
60     Ip4 = &Ip->v4;
61 
62     UnicodeSPrint (
63       Str,
64       (UINTN) 2 * IP4_STR_MAX_SIZE,
65       L"%d.%d.%d.%d",
66       (UINTN) Ip4->Addr[0],
67       (UINTN) Ip4->Addr[1],
68       (UINTN) Ip4->Addr[2],
69       (UINTN) Ip4->Addr[3]
70       );
71 
72     return ;
73   }
74 
75   Ip6   = &Ip->v6;
76   Short = FALSE;
77 
78   for (Index = 0; Index < 15; Index = Index + 2) {
79     if (!Short &&
80         Index % 2 == 0 &&
81         Ip6->Addr[Index] == 0 &&
82         Ip6->Addr[Index + 1] == 0
83         ) {
84       //
85       // Deal with the case of ::.
86       //
87       if (Index == 0) {
88         *Str       = L':';
89         *(Str + 1) = L':';
90         Str        = Str + 2;
91       } else {
92         *Str       = L':';
93         Str        = Str + 1;
94       }
95 
96       while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {
97         Index = Index + 2;
98       }
99 
100       Short = TRUE;
101 
102       if (Index == 16) {
103         //
104         // :: is at the end of the address.
105         //
106         *Str = L'\0';
107         break;
108       }
109     }
110 
111     ASSERT (Index < 15);
112 
113     if (Ip6->Addr[Index] == 0) {
114       Number = UnicodeSPrint (Str, 2 * IP_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);
115     } else {
116       if (Ip6->Addr[Index + 1] < 0x10) {
117         CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));
118       } else {
119         CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));
120       }
121 
122       Number = UnicodeSPrint (
123                  Str,
124                  2 * IP_STR_MAX_SIZE,
125                  (CONST CHAR16 *) FormatString,
126                  (UINTN) Ip6->Addr[Index],
127                  (UINTN) Ip6->Addr[Index + 1]
128                  );
129     }
130 
131     Str = Str + Number;
132 
133     if (Index + 2 == 16) {
134       *Str = L'\0';
135       if (*(Str - 1) == L':') {
136         *(Str - 1) = L'\0';
137       }
138     }
139   }
140 }
141 
142 /**
143   Check whether the input IP address is valid.
144 
145   @param[in]  Ip        The IP address.
146   @param[in]  IpMode    Indicates iSCSI running on IP4 or IP6 stack.
147 
148   @retval     TRUE      The input IP address is valid.
149   @retval     FALSE     Otherwise
150 
151 **/
152 BOOLEAN
IpIsUnicast(IN EFI_IP_ADDRESS * Ip,IN UINT8 IpMode)153 IpIsUnicast (
154   IN EFI_IP_ADDRESS *Ip,
155   IN  UINT8          IpMode
156   )
157 {
158   if (IpMode == IP_MODE_IP4) {
159     if (IP4_IS_UNSPECIFIED (NTOHL (Ip->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip->Addr[0])))   {
160       return FALSE;
161     }
162     return TRUE;
163   } else if (IpMode == IP_MODE_IP6) {
164     return NetIp6IsValidUnicast (&Ip->v6);
165   } else {
166     DEBUG ((DEBUG_ERROR, "IpMode %d is invalid when configuring the iSCSI target IP!\n", IpMode));
167     return FALSE;
168   }
169 }
170 
171 /**
172   Parse IsId in string format and convert it to binary.
173 
174   @param[in]        String  The buffer of the string to be parsed.
175   @param[in, out]   IsId    The buffer to store IsId.
176 
177   @retval EFI_SUCCESS              The operation finished successfully.
178   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
179 
180 **/
181 EFI_STATUS
IScsiParseIsIdFromString(IN CONST CHAR16 * String,IN OUT UINT8 * IsId)182 IScsiParseIsIdFromString (
183   IN CONST CHAR16                    *String,
184   IN OUT   UINT8                     *IsId
185   )
186 {
187   UINT8                          Index;
188   CHAR16                         *IsIdStr;
189   CHAR16                         TempStr[3];
190   UINTN                          NodeVal;
191   CHAR16                         PortString[ISCSI_NAME_IFR_MAX_SIZE];
192   EFI_INPUT_KEY                  Key;
193 
194   if ((String == NULL) || (IsId == NULL)) {
195     return EFI_INVALID_PARAMETER;
196   }
197 
198   IsIdStr = (CHAR16 *) String;
199 
200   if (StrLen (IsIdStr) != 6 && StrLen (IsIdStr) != 12) {
201     UnicodeSPrint (
202       PortString,
203       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
204       L"Error! Only last 3 bytes are configurable, please input 6 hex numbers for last 3 bytes only or 12 hex numbers for full SSID!\n"
205       );
206 
207     CreatePopUp (
208       EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
209       &Key,
210       PortString,
211       NULL
212       );
213 
214     return EFI_INVALID_PARAMETER;
215   }
216 
217   if (StrLen (IsIdStr) == 12) {
218     IsIdStr += 6;
219   }
220 
221   for (Index = 3; Index < 6; Index++) {
222     CopyMem (TempStr, IsIdStr, sizeof (TempStr));
223     TempStr[2] = L'\0';
224 
225     //
226     // Convert the string to IsId. StrHexToUintn stops at the first character
227     // that is not a valid hex character, '\0' here.
228     //
229     NodeVal = StrHexToUintn (TempStr);
230 
231     IsId[Index] = (UINT8) NodeVal;
232 
233     IsIdStr = IsIdStr + 2;
234   }
235 
236   return EFI_SUCCESS;
237 }
238 
239 /**
240   Convert IsId from binary to string format.
241 
242   @param[out]      String  The buffer to store the converted string.
243   @param[in]       IsId    The buffer to store IsId.
244 
245   @retval EFI_SUCCESS              The string converted successfully.
246   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
247 
248 **/
249 EFI_STATUS
IScsiConvertIsIdToString(OUT CHAR16 * String,IN UINT8 * IsId)250 IScsiConvertIsIdToString (
251   OUT CHAR16                         *String,
252   IN  UINT8                          *IsId
253   )
254 {
255   UINT8                          Index;
256   UINTN                          Number;
257 
258   if ((String == NULL) || (IsId == NULL)) {
259     return EFI_INVALID_PARAMETER;
260   }
261 
262   for (Index = 0; Index < 6; Index++) {
263     if (IsId[Index] <= 0xF) {
264       Number = UnicodeSPrint (
265                  String,
266                  2 * ISID_CONFIGURABLE_STORAGE,
267                  L"0%X",
268                  (UINTN) IsId[Index]
269                  );
270     } else {
271       Number = UnicodeSPrint (
272                  String,
273                  2 * ISID_CONFIGURABLE_STORAGE,
274                  L"%X",
275                  (UINTN) IsId[Index]
276                  );
277 
278     }
279 
280     String = String + Number;
281   }
282 
283   *String = L'\0';
284 
285   return EFI_SUCCESS;
286 }
287 
288 /**
289   Get the Offset value specified by the input String.
290 
291   @param[in]  Configuration      A null-terminated Unicode string in
292                                  <ConfigString> format.
293   @param[in]  String             The string is "&OFFSET=".
294   @param[out] Value              The Offset value.
295 
296   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary
297                                  structures.
298   @retval EFI_SUCCESS            Value of <Number> is outputted in Number
299                                  successfully.
300 
301 **/
302 EFI_STATUS
IScsiGetValue(IN CONST EFI_STRING Configuration,IN CHAR16 * String,OUT UINTN * Value)303 IScsiGetValue (
304   IN  CONST EFI_STRING             Configuration,
305   IN  CHAR16                       *String,
306   OUT UINTN                        *Value
307   )
308 {
309   CHAR16                           *StringPtr;
310   CHAR16                           *TmpPtr;
311   CHAR16                           *Str;
312   CHAR16                           TmpStr[2];
313   UINTN                            Length;
314   UINTN                            Len;
315   UINTN                            Index;
316   UINT8                            *Buf;
317   UINT8                            DigitUint8;
318   EFI_STATUS                       Status;
319 
320   //
321   // Get Value.
322   //
323   Buf = NULL;
324   StringPtr = StrStr (Configuration, String);
325   ASSERT(StringPtr != NULL);
326   StringPtr += StrLen (String);
327   TmpPtr = StringPtr;
328 
329   while (*StringPtr != L'\0' && *StringPtr != L'&') {
330     StringPtr ++;
331   }
332   Length = StringPtr - TmpPtr;
333   Len = Length + 1;
334 
335   Str = AllocateZeroPool (Len * sizeof (CHAR16));
336   if (Str == NULL) {
337     Status = EFI_OUT_OF_RESOURCES;
338     goto Exit;
339   }
340 
341   CopyMem (Str, TmpPtr, Len * sizeof (CHAR16));
342   *(Str + Length) = L'\0';
343 
344   Len = (Len + 1) / 2;
345   Buf = (UINT8 *) AllocateZeroPool (Len);
346   if (Buf == NULL) {
347     Status = EFI_OUT_OF_RESOURCES;
348     goto Exit;
349   }
350 
351   ZeroMem (TmpStr, sizeof (TmpStr));
352   for (Index = 0; Index < Length; Index ++) {
353     TmpStr[0] = Str[Length - Index - 1];
354     DigitUint8 = (UINT8) StrHexToUint64 (TmpStr);
355     if ((Index & 1) == 0) {
356       Buf [Index/2] = DigitUint8;
357     } else {
358       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
359     }
360   }
361 
362   *Value = 0;
363   CopyMem (
364     Value,
365     Buf,
366     (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
367     );
368 
369   FreePool (Buf);
370   Status = EFI_SUCCESS;
371 
372 Exit:
373   if (Str != NULL) {
374     FreePool (Str);
375   }
376 
377   return Status;
378 }
379 
380 /**
381   Get the attempt config data from global structure by the ConfigIndex.
382 
383   @param[in]  AttemptConfigIndex     The unique index indicates the attempt.
384 
385   @return       Pointer to the attempt config data.
386   @retval NULL  The attempt configuration data cannot be found.
387 
388 **/
389 ISCSI_ATTEMPT_CONFIG_NVDATA *
IScsiConfigGetAttemptByConfigIndex(IN UINT8 AttemptConfigIndex)390 IScsiConfigGetAttemptByConfigIndex (
391   IN UINT8                     AttemptConfigIndex
392   )
393 {
394   LIST_ENTRY                   *Entry;
395   ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt;
396 
397   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
398     Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
399     if (Attempt->AttemptConfigIndex == AttemptConfigIndex) {
400       return Attempt;
401     }
402   }
403 
404   return NULL;
405 }
406 
407 
408 /**
409   Get the existing attempt config data from global structure by the NicIndex.
410 
411   @param[in]  NewAttempt         The created new attempt
412   @param[in]  IScsiMode          The IScsi Mode of the new attempt, Enabled or
413                                  Enabled for MPIO.
414 
415   @return                        Pointer to the existing attempt config data which
416                                  has the same NICIndex as the new created attempt.
417   @retval     NULL               The attempt with NicIndex does not exist.
418 
419 **/
420 ISCSI_ATTEMPT_CONFIG_NVDATA *
IScsiConfigGetAttemptByNic(IN ISCSI_ATTEMPT_CONFIG_NVDATA * NewAttempt,IN UINT8 IScsiMode)421 IScsiConfigGetAttemptByNic (
422   IN ISCSI_ATTEMPT_CONFIG_NVDATA *NewAttempt,
423   IN UINT8                       IScsiMode
424   )
425 {
426   LIST_ENTRY                   *Entry;
427   ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt;
428 
429   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
430     Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
431     if (Attempt != NewAttempt && Attempt->NicIndex == NewAttempt->NicIndex &&
432         Attempt->SessionConfigData.Enabled == IScsiMode) {
433       return Attempt;
434     }
435   }
436 
437   return NULL;
438 }
439 
440 /**
441   Extract the Index of the attempt list.
442 
443   @param[in]   AttemptNameList     The Name list of the Attempts.
444   @param[out]  AttemptIndexList    The Index list of the Attempts.
445   @param[in]   IsAddAttempts       If TRUE, Indicates add one or more attempts.
446                                    If FALSE, Indicates delete attempts or change attempt order.
447 
448   @retval EFI_SUCCESS              The Attempt list is valid.
449   @retval EFI_INVALID_PARAMETERS   The Attempt List is invalid.
450 
451 **/
452 EFI_STATUS
IScsiGetAttemptIndexList(IN CHAR16 * AttemptNameList,OUT UINT8 * AttemptIndexList,IN BOOLEAN IsAddAttempts)453 IScsiGetAttemptIndexList (
454   IN      CHAR16                    *AttemptNameList,
455      OUT  UINT8                     *AttemptIndexList,
456   IN      BOOLEAN                   IsAddAttempts
457 )
458 {
459   ISCSI_ATTEMPT_CONFIG_NVDATA   *AttemptConfigData;
460   CHAR16                        *AttemptStr;
461   UINT8                         AttemptIndex;
462   UINTN                         Len;
463   UINTN                         Index;
464 
465   Index = 0;
466 
467   if ((AttemptNameList == NULL) || (*AttemptNameList == L'\0')) {
468     return EFI_INVALID_PARAMETER;
469   }
470 
471   AttemptStr = AttemptNameList;
472   Len = StrLen (L"attempt:");
473 
474   while (*AttemptStr != L'\0') {
475     AttemptStr = StrStr (AttemptStr, L"attempt:");
476     if (AttemptStr == NULL) {
477       return EFI_INVALID_PARAMETER;
478     }
479     AttemptStr += Len;
480     AttemptIndex = (UINT8)(*AttemptStr - L'0');
481     AttemptConfigData  = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
482     if (IsAddAttempts) {
483       if ((AttemptConfigData != NULL) || ((AttemptIndex) > PcdGet8 (PcdMaxIScsiAttemptNumber))) {
484         return EFI_INVALID_PARAMETER;
485       }
486     } else {
487       if (AttemptConfigData == NULL) {
488         return EFI_INVALID_PARAMETER;
489       }
490     }
491 
492     AttemptIndexList[Index] = AttemptIndex;
493     Index ++;
494     AttemptStr += 2;
495   }
496   return EFI_SUCCESS;
497 }
498 
499 /**
500   Convert the iSCSI configuration data into the IFR data.
501 
502   @param[in]       Attempt                The iSCSI attempt config data.
503   @param[in, out]  IfrNvData              The IFR nv data.
504 
505 **/
506 VOID
IScsiConvertAttemptConfigDataToIfrNvData(IN ISCSI_ATTEMPT_CONFIG_NVDATA * Attempt,IN OUT ISCSI_CONFIG_IFR_NVDATA * IfrNvData)507 IScsiConvertAttemptConfigDataToIfrNvData (
508   IN ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt,
509   IN OUT ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
510   )
511 {
512   ISCSI_SESSION_CONFIG_NVDATA   *SessionConfigData;
513   ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;
514   EFI_IP_ADDRESS                Ip;
515   BOOLEAN                       DnsMode;
516 
517   //
518   // Normal session configuration parameters.
519   //
520   SessionConfigData                 = &Attempt->SessionConfigData;
521   IfrNvData->Enabled                = SessionConfigData->Enabled;
522   IfrNvData->IpMode                 = SessionConfigData->IpMode;
523   DnsMode                           = SessionConfigData->DnsMode;
524 
525   IfrNvData->InitiatorInfoFromDhcp  = SessionConfigData->InitiatorInfoFromDhcp;
526   IfrNvData->TargetInfoFromDhcp     = SessionConfigData->TargetInfoFromDhcp;
527   IfrNvData->TargetPort             = SessionConfigData->TargetPort;
528 
529   if (IfrNvData->IpMode == IP_MODE_IP4) {
530     CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
531     IScsiIpToStr (&Ip, FALSE, IfrNvData->LocalIp);
532     CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
533     IScsiIpToStr (&Ip, FALSE, IfrNvData->SubnetMask);
534     CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS));
535     IScsiIpToStr (&Ip, FALSE, IfrNvData->Gateway);
536     ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
537     if (SessionConfigData->TargetIp.v4.Addr[0] != '\0') {
538       CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS));
539       IScsiIpToStr (&Ip, FALSE, IfrNvData->TargetIp);
540     }
541 
542   } else if (IfrNvData->IpMode == IP_MODE_IP6) {
543     ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
544     if (SessionConfigData->TargetIp.v6.Addr[0] != '\0') {
545       IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp);
546       IScsiIpToStr (&Ip, TRUE, IfrNvData->TargetIp);
547     }
548   }
549 
550   AsciiStrToUnicodeStrS (
551     SessionConfigData->TargetName,
552     IfrNvData->TargetName,
553     sizeof (IfrNvData->TargetName) / sizeof (IfrNvData->TargetName[0])
554     );
555 
556   if (DnsMode) {
557     AsciiStrToUnicodeStrS (
558       SessionConfigData->TargetUrl,
559       IfrNvData->TargetIp,
560       sizeof (IfrNvData->TargetIp) / sizeof (IfrNvData->TargetIp[0])
561       );
562   }
563 
564   IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);
565   IScsiConvertIsIdToString (IfrNvData->IsId, SessionConfigData->IsId);
566 
567   IfrNvData->ConnectRetryCount = SessionConfigData->ConnectRetryCount;
568   IfrNvData->ConnectTimeout    = SessionConfigData->ConnectTimeout;
569 
570   //
571   // Authentication parameters.
572   //
573   IfrNvData->AuthenticationType = Attempt->AuthenticationType;
574 
575   if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
576     AuthConfigData      = &Attempt->AuthConfigData.CHAP;
577     IfrNvData->CHAPType = AuthConfigData->CHAPType;
578     AsciiStrToUnicodeStrS (
579       AuthConfigData->CHAPName,
580       IfrNvData->CHAPName,
581       sizeof (IfrNvData->CHAPName) / sizeof (IfrNvData->CHAPName[0])
582       );
583     AsciiStrToUnicodeStrS (
584       AuthConfigData->CHAPSecret,
585       IfrNvData->CHAPSecret,
586       sizeof (IfrNvData->CHAPSecret) / sizeof (IfrNvData->CHAPSecret[0])
587       );
588     AsciiStrToUnicodeStrS (
589       AuthConfigData->ReverseCHAPName,
590       IfrNvData->ReverseCHAPName,
591       sizeof (IfrNvData->ReverseCHAPName) / sizeof (IfrNvData->ReverseCHAPName[0])
592       );
593     AsciiStrToUnicodeStrS (
594       AuthConfigData->ReverseCHAPSecret,
595       IfrNvData->ReverseCHAPSecret,
596       sizeof (IfrNvData->ReverseCHAPSecret) / sizeof (IfrNvData->ReverseCHAPSecret[0])
597       );
598   }
599 
600   //
601   // Other parameters.
602   //
603   AsciiStrToUnicodeStrS (
604     Attempt->AttemptName,
605     IfrNvData->AttemptName,
606     sizeof (IfrNvData->AttemptName) / sizeof (IfrNvData->AttemptName[0])
607     );
608 }
609 
610 /**
611   Convert the iSCSI configuration data into the IFR data Which will be used
612   to extract the iSCSI Keyword configuration in <ConfigAltResp> format.
613 
614   @param[in, out]  IfrNvData              The IFR nv data.
615 
616 **/
617 VOID
618 EFIAPI
IScsiConvertAttemptConfigDataToIfrNvDataByKeyword(IN OUT ISCSI_CONFIG_IFR_NVDATA * IfrNvData)619 IScsiConvertAttemptConfigDataToIfrNvDataByKeyword (
620   IN OUT ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
621   )
622 {
623   LIST_ENTRY                    *Entry;
624   ISCSI_ATTEMPT_CONFIG_NVDATA   *Attempt;
625   ISCSI_SESSION_CONFIG_NVDATA   *SessionConfigData;
626   ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;
627   CHAR16                        AttemptNameList[ATTEMPT_NAME_LIST_SIZE];
628   ISCSI_NIC_INFO                *NicInfo;
629   CHAR16                        MacString[ISCSI_MAX_MAC_STRING_LEN];
630   EFI_IP_ADDRESS                Ip;
631   UINTN                         Index;
632   UINTN                         StringLen;
633 
634   NicInfo = NULL;
635   ZeroMem (AttemptNameList, sizeof (AttemptNameList));
636 
637   if ((mPrivate != NULL) && (mPrivate->AttemptCount != 0)) {
638     NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
639       Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
640       //
641       // Normal session configuration parameters.
642       //
643       SessionConfigData                 = &Attempt->SessionConfigData;
644 
645       ASSERT ((Attempt->AttemptConfigIndex > 0) && (Attempt->AttemptConfigIndex <= FixedPcdGet8 (PcdMaxIScsiAttemptNumber)));
646       Index   = Attempt->AttemptConfigIndex - 1;
647 
648       //
649       // Save the attempt to AttemptNameList as Attempt:1 Attempt:2
650       //
651       AsciiStrToUnicodeStrS (
652         Attempt->AttemptName,
653         AttemptNameList + StrLen (AttemptNameList),
654         ATTEMPT_NAME_LIST_SIZE - StrLen (AttemptNameList)
655       );
656 
657       StringLen = StrLen (AttemptNameList);
658       ASSERT (StringLen > 2);
659       *(AttemptNameList + StringLen - 2) = L':';
660       *(AttemptNameList + StringLen)     = L' ';
661 
662       AsciiStrToUnicodeStrS (
663         Attempt->AttemptName,
664         IfrNvData->ISCSIAttemptName  + ATTEMPT_NAME_SIZE * Index,
665         ATTEMPT_NAME_LIST_SIZE - ATTEMPT_NAME_SIZE * Index
666       );
667 
668       IfrNvData->ISCSIBootEnableList[Index]          = SessionConfigData->Enabled;
669       IfrNvData->ISCSIIpAddressTypeList[Index]       = SessionConfigData->IpMode;
670 
671       IfrNvData->ISCSIInitiatorInfoViaDHCP[Index]    = SessionConfigData->InitiatorInfoFromDhcp;
672       IfrNvData->ISCSITargetInfoViaDHCP[Index]       = SessionConfigData->TargetInfoFromDhcp;
673       IfrNvData->ISCSIConnectRetry[Index]            = SessionConfigData->ConnectRetryCount;
674       IfrNvData->ISCSIConnectTimeout[Index]          = SessionConfigData->ConnectTimeout;
675       IfrNvData->ISCSITargetTcpPort[Index]           = SessionConfigData->TargetPort;
676 
677       if (SessionConfigData->IpMode == IP_MODE_IP4) {
678         CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
679         IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorIpAddress);
680         CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
681         IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorNetmask);
682         CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS));
683         IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSIInitiatorGateway);
684         if (SessionConfigData->TargetIp.v4.Addr[0] != '\0') {
685           CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS));
686           IScsiIpToStr (&Ip, FALSE, IfrNvData->Keyword[Index].ISCSITargetIpAddress);
687         }
688       } else if (SessionConfigData->IpMode == IP_MODE_IP6) {
689         ZeroMem (IfrNvData->Keyword[Index].ISCSITargetIpAddress, sizeof (IfrNvData->TargetIp));
690         if (SessionConfigData->TargetIp.v6.Addr[0] != '\0') {
691           IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp);
692           IScsiIpToStr (&Ip, TRUE, IfrNvData->Keyword[Index].ISCSITargetIpAddress);
693         }
694       }
695 
696       AsciiStrToUnicodeStrS (
697         SessionConfigData->TargetName,
698         IfrNvData->Keyword[Index].ISCSITargetName,
699         ISCSI_NAME_MAX_SIZE
700         );
701 
702       if (SessionConfigData->DnsMode) {
703         AsciiStrToUnicodeStrS (
704           SessionConfigData->TargetUrl,
705           IfrNvData->Keyword[Index].ISCSITargetIpAddress,
706           sizeof (IfrNvData->Keyword[Index].ISCSITargetIpAddress) / sizeof (IfrNvData->Keyword[Index].ISCSITargetIpAddress[0])
707           );
708       }
709 
710       IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->Keyword[Index].ISCSILun);
711       IScsiConvertIsIdToString (IfrNvData->Keyword[Index].ISCSIIsId, SessionConfigData->IsId);
712 
713       IfrNvData->ISCSIAuthenticationMethod[Index]    = Attempt->AuthenticationType;
714 
715       if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
716         AuthConfigData      = &Attempt->AuthConfigData.CHAP;
717         IfrNvData->ISCSIChapType[Index] = AuthConfigData->CHAPType;
718         AsciiStrToUnicodeStrS (
719           AuthConfigData->CHAPName,
720           IfrNvData->Keyword[Index].ISCSIChapUsername,
721           ISCSI_CHAP_NAME_STORAGE
722           );
723 
724         AsciiStrToUnicodeStrS (
725           AuthConfigData->CHAPSecret,
726           IfrNvData->Keyword[Index].ISCSIChapSecret,
727           ISCSI_CHAP_SECRET_STORAGE
728           );
729 
730         AsciiStrToUnicodeStrS (
731           AuthConfigData->ReverseCHAPName,
732           IfrNvData->Keyword[Index].ISCSIReverseChapUsername,
733           ISCSI_CHAP_NAME_STORAGE
734           );
735 
736         AsciiStrToUnicodeStrS (
737           AuthConfigData->ReverseCHAPSecret,
738           IfrNvData->Keyword[Index].ISCSIReverseChapSecret,
739           ISCSI_CHAP_SECRET_STORAGE
740           );
741       }
742     }
743     CopyMem(IfrNvData->ISCSIDisplayAttemptList, AttemptNameList, ATTEMPT_NAME_LIST_SIZE);
744 
745     ZeroMem (IfrNvData->ISCSIMacAddr, sizeof (IfrNvData->ISCSIMacAddr));
746     NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
747       NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
748       IScsiMacAddrToStr (
749         &NicInfo->PermanentAddress,
750         NicInfo->HwAddressSize,
751         NicInfo->VlanId,
752         MacString
753         );
754       CopyMem (
755         IfrNvData->ISCSIMacAddr + StrLen (IfrNvData->ISCSIMacAddr),
756         MacString,
757         StrLen (MacString) * sizeof (CHAR16)
758         );
759 
760       *(IfrNvData->ISCSIMacAddr + StrLen (IfrNvData->ISCSIMacAddr)) = L'/';
761     }
762 
763     StringLen = StrLen (IfrNvData->ISCSIMacAddr);
764     if (StringLen > 0) {
765       *(IfrNvData->ISCSIMacAddr + StringLen - 1) = L'\0';
766     }
767   }
768 }
769 
770 /**
771   Convert the IFR data to iSCSI configuration data.
772 
773   @param[in]       IfrNvData              Point to ISCSI_CONFIG_IFR_NVDATA.
774   @param[in, out]  Attempt                The iSCSI attempt config data.
775 
776   @retval EFI_INVALID_PARAMETER  Any input or configured parameter is invalid.
777   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
778   @retval EFI_OUT_OF_RESOURCES   The operation is failed due to lack of resources.
779   @retval EFI_ABORTED            The operation is aborted.
780   @retval EFI_SUCCESS            The operation is completed successfully.
781 
782 **/
783 EFI_STATUS
IScsiConvertIfrNvDataToAttemptConfigData(IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData,IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA * Attempt)784 IScsiConvertIfrNvDataToAttemptConfigData (
785   IN ISCSI_CONFIG_IFR_NVDATA          *IfrNvData,
786   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA  *Attempt
787   )
788 {
789   EFI_IP_ADDRESS              HostIp;
790   EFI_IP_ADDRESS              SubnetMask;
791   EFI_IP_ADDRESS              Gateway;
792   CHAR16                      *MacString;
793   CHAR16                      *AttemptName1;
794   CHAR16                      *AttemptName2;
795   ISCSI_ATTEMPT_CONFIG_NVDATA *ExistAttempt;
796   ISCSI_ATTEMPT_CONFIG_NVDATA *SameNicAttempt;
797   CHAR16                      IScsiMode[64];
798   CHAR16                      IpMode[64];
799   ISCSI_NIC_INFO              *NicInfo;
800   EFI_INPUT_KEY               Key;
801   UINT8                       *AttemptConfigOrder;
802   UINTN                       AttemptConfigOrderSize;
803   UINT8                       *AttemptOrderTmp;
804   UINTN                       TotalNumber;
805   EFI_STATUS                  Status;
806 
807   if (IfrNvData == NULL || Attempt == NULL) {
808     return EFI_INVALID_PARAMETER;
809   }
810 
811   //
812   // Update those fields which don't have INTERACTIVE attribute.
813   //
814   Attempt->SessionConfigData.ConnectRetryCount     = IfrNvData->ConnectRetryCount;
815   Attempt->SessionConfigData.ConnectTimeout        = IfrNvData->ConnectTimeout;
816   Attempt->SessionConfigData.IpMode                = IfrNvData->IpMode;
817 
818   if (IfrNvData->IpMode < IP_MODE_AUTOCONFIG) {
819     Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;
820     Attempt->SessionConfigData.TargetPort            = IfrNvData->TargetPort;
821 
822     if (Attempt->SessionConfigData.TargetPort == 0) {
823       Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
824     }
825 
826     Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;
827   }
828 
829   Attempt->AuthenticationType = IfrNvData->AuthenticationType;
830 
831   if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
832     Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->CHAPType;
833   }
834 
835   //
836   // Only do full parameter validation if iSCSI is enabled on this device.
837   //
838   if (IfrNvData->Enabled != ISCSI_DISABLED) {
839     if (Attempt->SessionConfigData.ConnectTimeout < CONNECT_MIN_TIMEOUT) {
840       CreatePopUp (
841         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
842         &Key,
843         L"Connection Establishing Timeout is less than minimum value 100ms.",
844         NULL
845         );
846 
847       return EFI_INVALID_PARAMETER;
848     }
849 
850     //
851     // Validate the address configuration of the Initiator if DHCP isn't
852     // deployed.
853     //
854     if (!Attempt->SessionConfigData.InitiatorInfoFromDhcp) {
855       CopyMem (&HostIp.v4, &Attempt->SessionConfigData.LocalIp, sizeof (HostIp.v4));
856       CopyMem (&SubnetMask.v4, &Attempt->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
857       CopyMem (&Gateway.v4, &Attempt->SessionConfigData.Gateway, sizeof (Gateway.v4));
858 
859       if ((Gateway.Addr[0] != 0)) {
860         if (SubnetMask.Addr[0] == 0) {
861           CreatePopUp (
862             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
863             &Key,
864             L"Gateway address is set but subnet mask is zero.",
865             NULL
866             );
867 
868           return EFI_INVALID_PARAMETER;
869         } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
870           CreatePopUp (
871             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
872             &Key,
873             L"Local IP and Gateway are not in the same subnet.",
874             NULL
875             );
876 
877           return EFI_INVALID_PARAMETER;
878         }
879       }
880     }
881     //
882     // Validate target configuration if DHCP isn't deployed.
883     //
884     if (!Attempt->SessionConfigData.TargetInfoFromDhcp && Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {
885       if (!Attempt->SessionConfigData.DnsMode) {
886         if (!IpIsUnicast (&Attempt->SessionConfigData.TargetIp, IfrNvData->IpMode)) {
887           CreatePopUp (
888             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
889             &Key,
890             L"Target IP is invalid!",
891             NULL
892             );
893           return EFI_INVALID_PARAMETER;
894         }
895       } else {
896         if (Attempt->SessionConfigData.TargetUrl[0] == '\0') {
897           CreatePopUp (
898             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
899             &Key,
900             L"iSCSI target Url should not be NULL!",
901             NULL
902             );
903           return EFI_INVALID_PARAMETER;
904         }
905       }
906 
907       //
908       // Validate iSCSI target name configuration again:
909       // The format of iSCSI target name is already verified in IScsiFormCallback() when
910       // user input the name; here we only check the case user does not input the name.
911       //
912       if (Attempt->SessionConfigData.TargetName[0] == '\0') {
913         CreatePopUp (
914           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
915           &Key,
916           L"iSCSI target name is NULL!",
917           NULL
918           );
919         return EFI_INVALID_PARAMETER;
920       }
921     }
922 
923     //
924     // Validate the authentication info.
925     //
926     if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
927       if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
928         CreatePopUp (
929           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
930           &Key,
931           L"CHAP Name or CHAP Secret is invalid!",
932           NULL
933           );
934 
935         return EFI_INVALID_PARAMETER;
936       }
937 
938       if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
939           ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
940           ) {
941         CreatePopUp (
942           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
943           &Key,
944           L"Reverse CHAP Name or Reverse CHAP Secret is invalid!",
945           NULL
946           );
947         return EFI_INVALID_PARAMETER;
948       }
949     }
950 
951     //
952     // Check whether this attempt uses NIC which is already used by existing attempt.
953     //
954     SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled);
955     if (SameNicAttempt != NULL) {
956       AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16));
957       if (AttemptName1 == NULL) {
958         return EFI_OUT_OF_RESOURCES;
959       }
960 
961       AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16));
962       if (AttemptName2 == NULL) {
963         FreePool (AttemptName1);
964         return EFI_OUT_OF_RESOURCES;
965       }
966 
967       AsciiStrToUnicodeStrS (Attempt->AttemptName, AttemptName1, ATTEMPT_NAME_SIZE);
968       AsciiStrToUnicodeStrS (SameNicAttempt->AttemptName, AttemptName2, ATTEMPT_NAME_SIZE);
969 
970       UnicodeSPrint (
971         mPrivate->PortString,
972         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
973         L"Warning! Attempt \"%s\" uses same NIC as Attempt \"%s\".",
974         AttemptName1,
975         AttemptName2
976         );
977 
978       CreatePopUp (
979         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
980         &Key,
981         mPrivate->PortString,
982         NULL
983         );
984 
985       FreePool (AttemptName1);
986       FreePool (AttemptName2);
987     }
988   }
989 
990   //
991   // Update the iSCSI Mode data and record it in attempt help info.
992   //
993   if (IfrNvData->Enabled == ISCSI_DISABLED) {
994     UnicodeSPrint (IScsiMode, 64, L"Disabled");
995   } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
996     UnicodeSPrint (IScsiMode, 64, L"Enabled");
997   } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
998     UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
999   }
1000 
1001   if (IfrNvData->IpMode == IP_MODE_IP4) {
1002     UnicodeSPrint (IpMode, 64, L"IP4");
1003   } else if (IfrNvData->IpMode == IP_MODE_IP6) {
1004     UnicodeSPrint (IpMode, 64, L"IP6");
1005   } else if (IfrNvData->IpMode == IP_MODE_AUTOCONFIG) {
1006     UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1007   }
1008 
1009   NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);
1010   if (NicInfo == NULL) {
1011     return EFI_NOT_FOUND;
1012   }
1013 
1014   MacString = (CHAR16 *) AllocateZeroPool (ISCSI_MAX_MAC_STRING_LEN * sizeof (CHAR16));
1015   if (MacString == NULL) {
1016     return EFI_OUT_OF_RESOURCES;
1017   }
1018 
1019   AsciiStrToUnicodeStrS (Attempt->MacString, MacString, ISCSI_MAX_MAC_STRING_LEN);
1020 
1021   UnicodeSPrint (
1022     mPrivate->PortString,
1023     (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1024     L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1025     MacString,
1026     NicInfo->BusNumber,
1027     NicInfo->DeviceNumber,
1028     NicInfo->FunctionNumber,
1029     IScsiMode,
1030     IpMode
1031     );
1032 
1033   Attempt->AttemptTitleHelpToken = HiiSetString (
1034                                      mCallbackInfo->RegisteredHandle,
1035                                      Attempt->AttemptTitleHelpToken,
1036                                      mPrivate->PortString,
1037                                      NULL
1038                                      );
1039   if (Attempt->AttemptTitleHelpToken == 0) {
1040     FreePool (MacString);
1041     return EFI_OUT_OF_RESOURCES;
1042   }
1043 
1044   //
1045   // Check whether this attempt is an existing one.
1046   //
1047   ExistAttempt = IScsiConfigGetAttemptByConfigIndex (Attempt->AttemptConfigIndex);
1048   if (ExistAttempt != NULL) {
1049     ASSERT (ExistAttempt == Attempt);
1050 
1051     if (IfrNvData->Enabled == ISCSI_DISABLED &&
1052         Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1053 
1054       //
1055       // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled".
1056       //
1057       if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1058         if (mPrivate->MpioCount < 1) {
1059           return EFI_ABORTED;
1060         }
1061 
1062         if (--mPrivate->MpioCount == 0) {
1063           mPrivate->EnableMpio = FALSE;
1064         }
1065       } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
1066         if (mPrivate->SinglePathCount < 1) {
1067           return EFI_ABORTED;
1068         }
1069         mPrivate->SinglePathCount--;
1070       }
1071 
1072     } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO &&
1073                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
1074       //
1075       // User updates the Attempt from "Enabled" to "Enabled for MPIO".
1076       //
1077       if (mPrivate->SinglePathCount < 1) {
1078         return EFI_ABORTED;
1079       }
1080 
1081       mPrivate->EnableMpio = TRUE;
1082       mPrivate->MpioCount++;
1083       mPrivate->SinglePathCount--;
1084 
1085     } else if (IfrNvData->Enabled == ISCSI_ENABLED &&
1086                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1087       //
1088       // User updates the Attempt from "Enabled for MPIO" to "Enabled".
1089       //
1090       if (mPrivate->MpioCount < 1) {
1091         return EFI_ABORTED;
1092       }
1093 
1094       if (--mPrivate->MpioCount == 0) {
1095         mPrivate->EnableMpio = FALSE;
1096       }
1097       mPrivate->SinglePathCount++;
1098 
1099     } else if (IfrNvData->Enabled != ISCSI_DISABLED &&
1100                Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {
1101       //
1102       // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO".
1103       //
1104       if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
1105         mPrivate->EnableMpio = TRUE;
1106         mPrivate->MpioCount++;
1107 
1108       } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
1109         mPrivate->SinglePathCount++;
1110       }
1111     }
1112 
1113   } else if (ExistAttempt == NULL) {
1114     //
1115     // When a new attempt is created, pointer of the attempt is saved to
1116     // mCallbackInfo->Current in IScsiConfigProcessDefault. If input Attempt
1117     // does not match any existing attempt, it should be a new created attempt.
1118     // Save it to system now.
1119     //
1120 
1121     //
1122     // Save current order number for this attempt.
1123     //
1124     AttemptConfigOrder = IScsiGetVariableAndSize (
1125                            L"AttemptOrder",
1126                            &gIScsiConfigGuid,
1127                            &AttemptConfigOrderSize
1128                            );
1129 
1130     TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);
1131     TotalNumber++;
1132 
1133     //
1134     // Append the new created attempt order to the end.
1135     //
1136     AttemptOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8));
1137     if (AttemptOrderTmp == NULL) {
1138       if (AttemptConfigOrder != NULL) {
1139         FreePool (AttemptConfigOrder);
1140       }
1141       return EFI_OUT_OF_RESOURCES;
1142     }
1143 
1144     if (AttemptConfigOrder != NULL) {
1145       CopyMem (AttemptOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize);
1146       FreePool (AttemptConfigOrder);
1147     }
1148 
1149     AttemptOrderTmp[TotalNumber - 1] = Attempt->AttemptConfigIndex;
1150     AttemptConfigOrder               = AttemptOrderTmp;
1151     AttemptConfigOrderSize           = TotalNumber * sizeof (UINT8);
1152 
1153     Status = gRT->SetVariable (
1154                     L"AttemptOrder",
1155                     &gIScsiConfigGuid,
1156                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1157                     AttemptConfigOrderSize,
1158                     AttemptConfigOrder
1159                     );
1160     FreePool (AttemptConfigOrder);
1161     if (EFI_ERROR (Status)) {
1162       return Status;
1163     }
1164 
1165     //
1166     // Insert new created attempt to array.
1167     //
1168     InsertTailList (&mPrivate->AttemptConfigs, &Attempt->Link);
1169     mPrivate->AttemptCount++;
1170 
1171     if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
1172       //
1173       // This new Attempt is enabled for MPIO; enable the multipath mode.
1174       //
1175       mPrivate->EnableMpio = TRUE;
1176       mPrivate->MpioCount++;
1177     } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
1178       mPrivate->SinglePathCount++;
1179     }
1180 
1181     IScsiConfigUpdateAttempt ();
1182   }
1183   Attempt->SessionConfigData.Enabled = IfrNvData->Enabled;
1184 
1185   //
1186   // Record the user configuration information in NVR.
1187   //
1188   UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", Attempt->AttemptConfigIndex);
1189 
1190   FreePool (MacString);
1191 
1192   return gRT->SetVariable (
1193                 mPrivate->PortString,
1194                 &gEfiIScsiInitiatorNameProtocolGuid,
1195                 ISCSI_CONFIG_VAR_ATTR,
1196                 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1197                 Attempt
1198                 );
1199 }
1200 
1201 /**
1202   Convert the IFR data configured by keyword to iSCSI configuration data.
1203 
1204   @param[in]  IfrNvData      Point to ISCSI_CONFIG_IFR_NVDATA.
1205   @param[in]  OffSet         The offset of the variable to the configuration structure.
1206 
1207   @retval EFI_INVALID_PARAMETER  Any input or configured parameter is invalid.
1208   @retval EFI_SUCCESS            The operation is completed successfully.
1209 
1210 **/
1211 EFI_STATUS
IScsiConvertlfrNvDataToAttemptConfigDataByKeyword(IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData,IN UINTN OffSet)1212 IScsiConvertlfrNvDataToAttemptConfigDataByKeyword (
1213   IN ISCSI_CONFIG_IFR_NVDATA          *IfrNvData,
1214   IN UINTN                             OffSet
1215   )
1216 {
1217   ISCSI_ATTEMPT_CONFIG_NVDATA      *Attempt;
1218   UINT8                            AttemptIndex;
1219   UINT8                            Index;
1220   UINT8                            ChapSecretLen;
1221   UINT8                            ReverseChapSecretLen;
1222   CHAR16                           *AttemptName1;
1223   CHAR16                           *AttemptName2;
1224   ISCSI_ATTEMPT_CONFIG_NVDATA      *SameNicAttempt;
1225   CHAR8                            LunString[ISCSI_LUN_STR_MAX_LEN];
1226   CHAR8                            IScsiName[ISCSI_NAME_MAX_SIZE];
1227   CHAR8                            IpString[IP_STR_MAX_SIZE];
1228   EFI_IP_ADDRESS                   HostIp;
1229   EFI_IP_ADDRESS                   SubnetMask;
1230   EFI_IP_ADDRESS                   Gateway;
1231   EFI_INPUT_KEY                    Key;
1232   UINT64                           Lun;
1233   EFI_STATUS                       Status;
1234 
1235   Attempt = NULL;
1236   ZeroMem (IScsiName, sizeof (IScsiName));
1237 
1238   if (OffSet < ATTEMPT_BOOTENABLE_VAR_OFFSET) {
1239     return EFI_SUCCESS;
1240 
1241   } else if ((OffSet >= ATTEMPT_BOOTENABLE_VAR_OFFSET) && (OffSet < ATTEMPT_ADDRESS_TYPE_VAR_OFFSET)) {
1242     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_BOOTENABLE_VAR_OFFSET) + 1);
1243     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1244     if (Attempt == NULL) {
1245       return EFI_INVALID_PARAMETER;
1246     }
1247     IfrNvData->Enabled = IfrNvData->ISCSIBootEnableList[AttemptIndex - 1];
1248     //
1249     // Validate the configuration of attempt.
1250     //
1251     if (IfrNvData->Enabled != ISCSI_DISABLED) {
1252       //
1253       // Check whether this attempt uses NIC which is already used by existing attempt.
1254       //
1255       SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled);
1256       if (SameNicAttempt != NULL) {
1257         AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16));
1258         if (AttemptName1 == NULL) {
1259           return EFI_OUT_OF_RESOURCES;
1260         }
1261 
1262         AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_SIZE * sizeof (CHAR16));
1263         if (AttemptName2 == NULL) {
1264           FreePool (AttemptName1);
1265           return EFI_OUT_OF_RESOURCES;
1266         }
1267 
1268         AsciiStrToUnicodeStrS (Attempt->AttemptName, AttemptName1, ATTEMPT_NAME_SIZE);
1269         AsciiStrToUnicodeStrS (SameNicAttempt->AttemptName, AttemptName2, ATTEMPT_NAME_SIZE);
1270 
1271         UnicodeSPrint (
1272           mPrivate->PortString,
1273           (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1274           L"Warning! \"%s\" uses same NIC as Attempt \"%s\".",
1275           AttemptName1,
1276           AttemptName2
1277           );
1278 
1279         CreatePopUp (
1280           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1281           &Key,
1282           mPrivate->PortString,
1283           NULL
1284           );
1285 
1286         FreePool (AttemptName1);
1287         FreePool (AttemptName2);
1288       }
1289     }
1290 
1291     if (IfrNvData->Enabled == ISCSI_DISABLED &&
1292         Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1293 
1294       //
1295       // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled".
1296       //
1297       if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1298         if (mPrivate->MpioCount < 1) {
1299           return EFI_ABORTED;
1300         }
1301 
1302         if (--mPrivate->MpioCount == 0) {
1303           mPrivate->EnableMpio = FALSE;
1304         }
1305       } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
1306         if (mPrivate->SinglePathCount < 1) {
1307           return EFI_ABORTED;
1308         }
1309         mPrivate->SinglePathCount--;
1310       }
1311 
1312     } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO &&
1313                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {
1314       //
1315       // User updates the Attempt from "Enabled" to "Enabled for MPIO".
1316       //
1317       if (mPrivate->SinglePathCount < 1) {
1318         return EFI_ABORTED;
1319       }
1320 
1321       mPrivate->EnableMpio = TRUE;
1322       mPrivate->MpioCount++;
1323       mPrivate->SinglePathCount--;
1324 
1325     } else if (IfrNvData->Enabled == ISCSI_ENABLED &&
1326                Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1327       //
1328       // User updates the Attempt from "Enabled for MPIO" to "Enabled".
1329       //
1330       if (mPrivate->MpioCount < 1) {
1331         return EFI_ABORTED;
1332       }
1333 
1334       if (--mPrivate->MpioCount == 0) {
1335         mPrivate->EnableMpio = FALSE;
1336       }
1337       mPrivate->SinglePathCount++;
1338 
1339     } else if (IfrNvData->Enabled != ISCSI_DISABLED &&
1340                Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {
1341       //
1342       // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO".
1343       //
1344       if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {
1345         mPrivate->EnableMpio = TRUE;
1346         mPrivate->MpioCount++;
1347 
1348       } else if (IfrNvData->Enabled == ISCSI_ENABLED) {
1349         mPrivate->SinglePathCount++;
1350       }
1351     }
1352     Attempt->SessionConfigData.Enabled = IfrNvData->Enabled;
1353 
1354   } else if ((OffSet >= ATTEMPT_ADDRESS_TYPE_VAR_OFFSET) && (OffSet < ATTEMPT_CONNECT_RETRY_VAR_OFFSET)) {
1355     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_ADDRESS_TYPE_VAR_OFFSET) + 1);
1356     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1357     if (Attempt == NULL) {
1358       return EFI_INVALID_PARAMETER;
1359     }
1360     Attempt->SessionConfigData.IpMode = IfrNvData->ISCSIIpAddressTypeList[AttemptIndex - 1];
1361     if (Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {
1362       Attempt->AutoConfigureMode = 0;
1363     }
1364 
1365   } else if ((OffSet >= ATTEMPT_CONNECT_RETRY_VAR_OFFSET) && (OffSet < ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET)) {
1366     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CONNECT_RETRY_VAR_OFFSET) + 1);
1367     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1368     if (Attempt == NULL) {
1369       return EFI_INVALID_PARAMETER;
1370     }
1371 
1372     if (IfrNvData->ISCSIConnectRetry[AttemptIndex - 1] > CONNECT_MAX_RETRY) {
1373       CreatePopUp (
1374           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1375           &Key,
1376           L"The minimum value is 0 and the maximum is 16. 0 means no retry.",
1377           NULL
1378           );
1379       return EFI_INVALID_PARAMETER;
1380     }
1381     Attempt->SessionConfigData.ConnectRetryCount = IfrNvData->ISCSIConnectRetry[AttemptIndex - 1];
1382 
1383   } else if ((OffSet >= ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET)) {
1384     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET) / 2 + 1);
1385     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1386     if (Attempt == NULL) {
1387       return EFI_INVALID_PARAMETER;
1388     }
1389 
1390     if ((IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1] < CONNECT_MIN_TIMEOUT) ||
1391         (IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1] > CONNECT_MAX_TIMEOUT)) {
1392       CreatePopUp (
1393         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1394         &Key,
1395         L"The minimum value is 100 milliseconds and the maximum is 20 seconds.",
1396         NULL
1397         );
1398       return EFI_INVALID_PARAMETER;
1399     }
1400 
1401     Attempt->SessionConfigData.ConnectTimeout = IfrNvData->ISCSIConnectTimeout[AttemptIndex - 1];
1402     if (Attempt->SessionConfigData.ConnectTimeout == 0) {
1403       Attempt->SessionConfigData.ConnectTimeout = CONNECT_DEFAULT_TIMEOUT;
1404     }
1405 
1406   } else if ((OffSet >= ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET)) {
1407     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET) + 1);
1408     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1409     if (Attempt == NULL) {
1410       return EFI_INVALID_PARAMETER;
1411     }
1412     Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->ISCSIInitiatorInfoViaDHCP[AttemptIndex - 1];
1413 
1414   } else if ((OffSet >= ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET)) {
1415     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET) + 1);
1416     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1417     if (Attempt == NULL) {
1418       return EFI_INVALID_PARAMETER;
1419     }
1420 
1421     if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (Attempt->SessionConfigData.InitiatorInfoFromDhcp)) {
1422       Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->ISCSITargetInfoViaDHCP[AttemptIndex - 1];
1423     } else {
1424       CreatePopUp (
1425         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1426         &Key,
1427         L"Invalid Configuration, Check value of IpMode or Enable DHCP!",
1428         NULL
1429         );
1430       return EFI_INVALID_PARAMETER;
1431     }
1432 
1433   } else if ((OffSet >= ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET) && (OffSet < ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET)) {
1434     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET) / 2 + 1);
1435     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1436     if (Attempt == NULL) {
1437       return EFI_INVALID_PARAMETER;
1438     }
1439     if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) {
1440       Attempt->SessionConfigData.TargetPort = IfrNvData->ISCSITargetTcpPort[AttemptIndex - 1];
1441       if (Attempt->SessionConfigData.TargetPort == 0) {
1442         Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
1443       }
1444     } else {
1445       CreatePopUp (
1446         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1447         &Key,
1448         L"Invalid Configuration, Check value of IpMode or Target Via DHCP!",
1449         NULL
1450         );
1451       return EFI_INVALID_PARAMETER;
1452     }
1453 
1454   } else if ((OffSet >= ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET) && (OffSet < ATTEMPT_CHARTYPE_VAR_OFFSET)) {
1455     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET) + 1);
1456     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1457     if (Attempt == NULL) {
1458       return EFI_INVALID_PARAMETER;
1459     }
1460 
1461     Attempt->AuthenticationType = IfrNvData->ISCSIAuthenticationMethod[AttemptIndex - 1];
1462 
1463   } else if ((OffSet >= ATTEMPT_CHARTYPE_VAR_OFFSET) && (OffSet < ATTEMPT_ISID_VAR_OFFSET)) {
1464     AttemptIndex = (UINT8) ((OffSet - ATTEMPT_CHARTYPE_VAR_OFFSET) + 1);
1465     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1466     if (Attempt == NULL) {
1467       return EFI_INVALID_PARAMETER;
1468     }
1469     if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
1470       Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->ISCSIChapType[AttemptIndex - 1];
1471     }
1472 
1473   } else if (OffSet >= ATTEMPT_ISID_VAR_OFFSET) {
1474     Index = (UINT8) ((OffSet - ATTEMPT_ISID_VAR_OFFSET) / sizeof (KEYWORD_STR));
1475     AttemptIndex = Index + 1;
1476     Attempt = IScsiConfigGetAttemptByConfigIndex (AttemptIndex);
1477     if (Attempt == NULL) {
1478       return EFI_INVALID_PARAMETER;
1479     }
1480 
1481     OffSet = OffSet - Index * sizeof (KEYWORD_STR);
1482 
1483     if ((OffSet >= ATTEMPT_ISID_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET)) {
1484       IScsiParseIsIdFromString (IfrNvData->Keyword[Index].ISCSIIsId, Attempt->SessionConfigData.IsId);
1485 
1486     }  else if ((OffSet >= ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET)) {
1487       if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) {
1488         //
1489         // Config Local ip
1490         //
1491         Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorIpAddress, &HostIp.v4);
1492         if (EFI_ERROR (Status) || ((Attempt->SessionConfigData.SubnetMask.Addr[0] != 0) &&
1493              !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), NTOHL(*(UINT32*)Attempt->SessionConfigData.SubnetMask.Addr)))) {
1494           CreatePopUp (
1495             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1496             &Key,
1497             L"Invalid IP address!",
1498             NULL
1499             );
1500           return EFI_INVALID_PARAMETER;
1501         } else {
1502           CopyMem (&Attempt->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
1503         }
1504       } else {
1505         CreatePopUp (
1506           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1507           &Key,
1508           L"Invalid Configuration, Check value of IpMode or Enable DHCP!",
1509           NULL
1510           );
1511         return EFI_INVALID_PARAMETER;
1512       }
1513 
1514     } else if ((OffSet >= ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET) && (OffSet < ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET)) {
1515       if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) {
1516         Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorNetmask, &SubnetMask.v4);
1517         if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
1518           CreatePopUp (
1519             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1520             &Key,
1521             L"Invalid Subnet Mask!",
1522             NULL
1523             );
1524           return EFI_INVALID_PARAMETER;
1525         } else {
1526           CopyMem (&Attempt->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
1527         }
1528       } else {
1529         CreatePopUp (
1530           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1531           &Key,
1532           L"Invalid Configuration, Check value of IpMode or Enable DHCP!",
1533           NULL
1534           );
1535         return EFI_INVALID_PARAMETER;
1536       }
1537 
1538     } else if ((OffSet >= ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_NAME_VAR_OFFSET)) {
1539       if ((Attempt->SessionConfigData.IpMode == IP_MODE_IP4) && (!Attempt->SessionConfigData.InitiatorInfoFromDhcp)) {
1540         Status = NetLibStrToIp4 (IfrNvData->Keyword[Index].ISCSIInitiatorGateway, &Gateway.v4);
1541         if (EFI_ERROR (Status) ||
1542           ((Gateway.Addr[0] != 0) && (Attempt->SessionConfigData.SubnetMask.Addr[0] != 0) &&
1543              !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL(*(UINT32*)Attempt->SessionConfigData.SubnetMask.Addr)))) {
1544           CreatePopUp (
1545             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1546             &Key,
1547             L"Invalid Gateway!",
1548             NULL
1549             );
1550           return EFI_INVALID_PARAMETER;
1551         } else {
1552           CopyMem (&Attempt->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
1553         }
1554       } else {
1555         CreatePopUp (
1556           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1557           &Key,
1558           L"Invalid Configuration, Check value of IpMode or Enable DHCP!",
1559           NULL
1560           );
1561         return EFI_INVALID_PARAMETER;
1562       }
1563 
1564     } else if ((OffSet >= ATTEMPT_TARGET_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET)) {
1565       if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) {
1566         UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetName, IScsiName, ISCSI_NAME_MAX_SIZE);
1567         Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
1568         if (EFI_ERROR (Status)) {
1569           CreatePopUp (
1570             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1571             &Key,
1572             L"Invalid iSCSI Name!",
1573             NULL
1574             );
1575         } else {
1576           AsciiStrCpyS (Attempt->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName);
1577         }
1578         if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1579           if (Attempt->SessionConfigData.TargetName[0] == L'\0') {
1580             CreatePopUp (
1581               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1582               &Key,
1583               L"iSCSI target name is NULL!",
1584               NULL
1585               );
1586             return EFI_INVALID_PARAMETER;
1587           }
1588         }
1589       } else {
1590         CreatePopUp (
1591           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1592           &Key,
1593           L"Invalid Configuration, Check value of IpMode or Target Via DHCP!",
1594           NULL
1595           );
1596         return EFI_INVALID_PARAMETER;
1597       }
1598 
1599     } else if ((OffSet >= ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET) && (OffSet < ATTEMPT_LUN_VAR_OFFSET)) {
1600       if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (!Attempt->SessionConfigData.TargetInfoFromDhcp)) {
1601         UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetIpAddress, IpString, sizeof (IpString));
1602         Status = IScsiAsciiStrToIp (IpString, Attempt->SessionConfigData.IpMode, &HostIp);
1603         if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, Attempt->SessionConfigData.IpMode)) {
1604           Attempt->SessionConfigData.DnsMode = TRUE;
1605           ZeroMem (&Attempt->SessionConfigData.TargetIp, sizeof (Attempt->SessionConfigData.TargetIp));
1606           UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSITargetIpAddress, Attempt->SessionConfigData.TargetUrl, ISCSI_NAME_MAX_SIZE);
1607         } else {
1608           Attempt->SessionConfigData.DnsMode = FALSE;
1609           CopyMem (&Attempt->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp));
1610         }
1611       } else {
1612         CreatePopUp (
1613           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1614           &Key,
1615           L"Invalid Configuration, Check value of IpMode or Target Via DHCP!",
1616           NULL
1617           );
1618         return EFI_INVALID_PARAMETER;
1619       }
1620 
1621     } else if ((OffSet >= ATTEMPT_LUN_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_USER_NAME_VAR_OFFSET)) {
1622       if ((Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) && (Attempt->SessionConfigData.TargetInfoFromDhcp == 0)) {
1623         //
1624         // Config LUN.
1625         //
1626         UnicodeStrToAsciiStrS (IfrNvData->Keyword[Index].ISCSILun, LunString, ISCSI_LUN_STR_MAX_LEN);
1627         Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
1628         if (EFI_ERROR (Status)) {
1629           CreatePopUp (
1630             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1631             &Key,
1632             L"Invalid LUN string, Examples are: 4752-3A4F-6b7e-2F99, 6734-9-156f-127, 4186-9!",
1633             NULL
1634             );
1635         } else {
1636           CopyMem (&Attempt->SessionConfigData.BootLun, &Lun, sizeof (Lun));
1637         }
1638       } else {
1639         CreatePopUp (
1640           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1641           &Key,
1642           L"Invalid Configuration, Check value of IpMode or Target Via DHCP!",
1643           NULL
1644           );
1645         return EFI_INVALID_PARAMETER;
1646       }
1647 
1648     } else if ((OffSet >= ATTEMPT_CHAR_USER_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_SECRET_VAR_OFFSET)) {
1649       if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
1650         UnicodeStrToAsciiStrS (
1651           IfrNvData->Keyword[Index].ISCSIChapUsername,
1652           Attempt->AuthConfigData.CHAP.CHAPName,
1653           ISCSI_CHAP_NAME_STORAGE
1654           );
1655 
1656         if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1657           if (IfrNvData->Keyword[Index].ISCSIChapUsername[0] == L'\0') {
1658             CreatePopUp (
1659               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1660               &Key,
1661               L"CHAP Name is invalid!",
1662               NULL
1663               );
1664             return EFI_INVALID_PARAMETER;
1665           }
1666         }
1667       } else {
1668         CreatePopUp (
1669           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1670           &Key,
1671           L"Invalid Configuration, Check value of AuthenticationType!",
1672           NULL
1673           );
1674         return EFI_INVALID_PARAMETER;
1675       }
1676 
1677     } else if ((OffSet >= ATTEMPT_CHAR_SECRET_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET)) {
1678       if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
1679         ChapSecretLen = (UINT8)StrLen (IfrNvData->Keyword[Index].ISCSIChapSecret);
1680         UnicodeStrToAsciiStrS (
1681           IfrNvData->Keyword[Index].ISCSIChapSecret,
1682           Attempt->AuthConfigData.CHAP.CHAPSecret,
1683           ISCSI_CHAP_SECRET_STORAGE
1684           );
1685 
1686         if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1687           if ((ChapSecretLen < ISCSI_CHAP_SECRET_MIN_LEN) || (ChapSecretLen > ISCSI_CHAP_SECRET_MAX_LEN)) {
1688             CreatePopUp (
1689               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1690               &Key,
1691               L"The Chap Secret minimum length is 12 bytes and the maximum length is 16 bytes.",
1692               NULL
1693               );
1694             return EFI_INVALID_PARAMETER;
1695           }
1696         }
1697       } else {
1698         CreatePopUp (
1699           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1700           &Key,
1701           L"Invalid Configuration, Check value of AuthenticationType!",
1702           NULL
1703           );
1704         return EFI_INVALID_PARAMETER;
1705       }
1706 
1707     } else if ((OffSet >= ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET) && (OffSet < ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET)) {
1708       if (Attempt->AuthConfigData.CHAP.CHAPType == ISCSI_CHAP_MUTUAL) {
1709         UnicodeStrToAsciiStrS (
1710           IfrNvData->Keyword[Index].ISCSIReverseChapUsername,
1711           Attempt->AuthConfigData.CHAP.ReverseCHAPName,
1712           ISCSI_CHAP_NAME_STORAGE
1713           );
1714         if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1715           if (IfrNvData->Keyword[Index].ISCSIReverseChapUsername[0] == L'\0') {
1716             CreatePopUp (
1717               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1718               &Key,
1719               L"Reverse CHAP Name is invalid!",
1720               NULL
1721               );
1722             return EFI_INVALID_PARAMETER;
1723           }
1724         }
1725       } else {
1726         CreatePopUp (
1727           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1728           &Key,
1729           L"Invalid Configuration, Check value of AuthenticationType or Chap Type!",
1730           NULL
1731           );
1732         return EFI_INVALID_PARAMETER;
1733       }
1734 
1735     } else if (OffSet >= ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET) {
1736       if (Attempt->AuthConfigData.CHAP.CHAPType == ISCSI_CHAP_MUTUAL) {
1737         ReverseChapSecretLen = (UINT8)StrLen (IfrNvData->Keyword[Index].ISCSIReverseChapSecret);
1738         UnicodeStrToAsciiStrS (
1739           IfrNvData->Keyword[Index].ISCSIReverseChapSecret,
1740           Attempt->AuthConfigData.CHAP.ReverseCHAPSecret,
1741           ISCSI_CHAP_SECRET_STORAGE
1742           );
1743 
1744         if (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {
1745           if ((ReverseChapSecretLen < ISCSI_CHAP_SECRET_MIN_LEN) || (ReverseChapSecretLen > ISCSI_CHAP_SECRET_MAX_LEN)) {
1746             CreatePopUp (
1747               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1748               &Key,
1749               L"The Reverse CHAP Secret minimum length is 12 bytes and the maximum length is 16 bytes.",
1750               NULL
1751               );
1752             return EFI_INVALID_PARAMETER;
1753           }
1754         }
1755       } else {
1756         CreatePopUp (
1757           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1758           &Key,
1759           L"Invalid Configuration, Check value of AuthenticationType or Chap Type!",
1760           NULL
1761           );
1762         return EFI_INVALID_PARAMETER;
1763       }
1764     }
1765   }
1766 
1767 
1768 
1769   //
1770   // Record the user configuration information in NVR.
1771   //
1772   ASSERT (Attempt != NULL);
1773   UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", Attempt->AttemptConfigIndex);
1774   return gRT->SetVariable (
1775                 mPrivate->PortString,
1776                 &gEfiIScsiInitiatorNameProtocolGuid,
1777                 ISCSI_CONFIG_VAR_ATTR,
1778                 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1779                 Attempt
1780                 );
1781 
1782 }
1783 
1784 /**
1785   Create Hii Extend Label OpCode as the start opcode and end opcode. It is
1786   a help function.
1787 
1788   @param[in]  StartLabelNumber   The number of start label.
1789   @param[out] StartOpCodeHandle  Points to the start opcode handle.
1790   @param[out] StartLabel         Points to the created start opcode.
1791   @param[out] EndOpCodeHandle    Points to the end opcode handle.
1792   @param[out] EndLabel           Points to the created end opcode.
1793 
1794   @retval EFI_OUT_OF_RESOURCES   Do not have sufficient resource to finish this
1795                                  operation.
1796   @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.
1797   @retval EFI_SUCCESS            The operation is completed successfully.
1798 
1799 **/
1800 EFI_STATUS
IScsiCreateOpCode(IN UINT16 StartLabelNumber,OUT VOID ** StartOpCodeHandle,OUT EFI_IFR_GUID_LABEL ** StartLabel,OUT VOID ** EndOpCodeHandle,OUT EFI_IFR_GUID_LABEL ** EndLabel)1801 IScsiCreateOpCode (
1802   IN  UINT16                        StartLabelNumber,
1803   OUT VOID                          **StartOpCodeHandle,
1804   OUT EFI_IFR_GUID_LABEL            **StartLabel,
1805   OUT VOID                          **EndOpCodeHandle,
1806   OUT EFI_IFR_GUID_LABEL            **EndLabel
1807   )
1808 {
1809   EFI_STATUS                        Status;
1810   EFI_IFR_GUID_LABEL                *InternalStartLabel;
1811   EFI_IFR_GUID_LABEL                *InternalEndLabel;
1812 
1813   if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {
1814     return EFI_INVALID_PARAMETER;
1815   }
1816 
1817   *StartOpCodeHandle = NULL;
1818   *EndOpCodeHandle   = NULL;
1819   Status             = EFI_OUT_OF_RESOURCES;
1820 
1821   //
1822   // Initialize the container for dynamic opcodes.
1823   //
1824   *StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1825   if (*StartOpCodeHandle == NULL) {
1826     return Status;
1827   }
1828 
1829   *EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1830   if (*EndOpCodeHandle == NULL) {
1831     goto Exit;
1832   }
1833 
1834   //
1835   // Create Hii Extend Label OpCode as the start opcode.
1836   //
1837   InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1838                                                 *StartOpCodeHandle,
1839                                                 &gEfiIfrTianoGuid,
1840                                                 NULL,
1841                                                 sizeof (EFI_IFR_GUID_LABEL)
1842                                                 );
1843   if (InternalStartLabel == NULL) {
1844     goto Exit;
1845   }
1846 
1847   InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1848   InternalStartLabel->Number       = StartLabelNumber;
1849 
1850   //
1851   // Create Hii Extend Label OpCode as the end opcode.
1852   //
1853   InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1854                                               *EndOpCodeHandle,
1855                                               &gEfiIfrTianoGuid,
1856                                               NULL,
1857                                               sizeof (EFI_IFR_GUID_LABEL)
1858                                               );
1859   if (InternalEndLabel == NULL) {
1860     goto Exit;
1861   }
1862 
1863   InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1864   InternalEndLabel->Number       = LABEL_END;
1865 
1866   *StartLabel = InternalStartLabel;
1867   *EndLabel   = InternalEndLabel;
1868 
1869   return EFI_SUCCESS;
1870 
1871 Exit:
1872 
1873   if (*StartOpCodeHandle != NULL) {
1874     HiiFreeOpCodeHandle (*StartOpCodeHandle);
1875   }
1876 
1877   if (*EndOpCodeHandle != NULL) {
1878     HiiFreeOpCodeHandle (*EndOpCodeHandle);
1879   }
1880   return Status;
1881 }
1882 
1883 /**
1884   Update the MAIN form to display the configured attempts.
1885 
1886 **/
1887 VOID
IScsiConfigUpdateAttempt(VOID)1888 IScsiConfigUpdateAttempt (
1889   VOID
1890   )
1891 {
1892   LIST_ENTRY                    *Entry;
1893   ISCSI_ATTEMPT_CONFIG_NVDATA   *AttemptConfigData;
1894   VOID                          *StartOpCodeHandle;
1895   EFI_IFR_GUID_LABEL            *StartLabel;
1896   VOID                          *EndOpCodeHandle;
1897   EFI_IFR_GUID_LABEL            *EndLabel;
1898   EFI_STATUS                    Status;
1899 
1900   Status = IScsiCreateOpCode (
1901              ATTEMPT_ENTRY_LABEL,
1902              &StartOpCodeHandle,
1903              &StartLabel,
1904              &EndOpCodeHandle,
1905              &EndLabel
1906              );
1907   if (EFI_ERROR (Status)) {
1908     return ;
1909   }
1910 
1911   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
1912     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
1913     if (AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) {
1914       //
1915       // Update Attempt Help Info.
1916       //
1917       UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", (UINTN) AttemptConfigData->AttemptConfigIndex);
1918       AttemptConfigData->AttemptTitleToken = HiiSetString (
1919                                                mCallbackInfo->RegisteredHandle,
1920                                                0,
1921                                                mPrivate->PortString,
1922                                                NULL
1923                                                );
1924       if (AttemptConfigData->AttemptTitleToken == 0) {
1925         return ;
1926       }
1927 
1928       HiiCreateGotoOpCode (
1929         StartOpCodeHandle,                         // Container for dynamic created opcodes
1930         FORMID_ATTEMPT_FORM,                       // Form ID
1931         AttemptConfigData->AttemptTitleToken,      // Prompt text
1932         AttemptConfigData->AttemptTitleHelpToken,  // Help text
1933         EFI_IFR_FLAG_CALLBACK,                     // Question flag
1934         (UINT16) (KEY_ATTEMPT_ENTRY_BASE + AttemptConfigData->AttemptConfigIndex)   // Question ID
1935         );
1936     }
1937   }
1938 
1939   HiiUpdateForm (
1940     mCallbackInfo->RegisteredHandle, // HII handle
1941     &gIScsiConfigGuid,               // Formset GUID
1942     FORMID_MAIN_FORM,                // Form ID
1943     StartOpCodeHandle,               // Label for where to insert opcodes
1944     EndOpCodeHandle                  // Replace data
1945   );
1946 
1947   HiiFreeOpCodeHandle (StartOpCodeHandle);
1948   HiiFreeOpCodeHandle (EndOpCodeHandle);
1949 }
1950 
1951 /**
1952   Callback function when user presses "Add an Attempt".
1953 
1954   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
1955                                  operation.
1956   @retval EFI_SUCCESS            The operation is completed successfully.
1957 
1958 **/
1959 EFI_STATUS
IScsiConfigAddAttempt(VOID)1960 IScsiConfigAddAttempt (
1961   VOID
1962   )
1963 {
1964   LIST_ENTRY                    *Entry;
1965   ISCSI_NIC_INFO                *NicInfo;
1966   EFI_STRING_ID                 PortTitleToken;
1967   EFI_STRING_ID                 PortTitleHelpToken;
1968   CHAR16                        MacString[ISCSI_MAX_MAC_STRING_LEN];
1969   EFI_STATUS                    Status;
1970   VOID                          *StartOpCodeHandle;
1971   EFI_IFR_GUID_LABEL            *StartLabel;
1972   VOID                          *EndOpCodeHandle;
1973   EFI_IFR_GUID_LABEL            *EndLabel;
1974 
1975   Status = IScsiCreateOpCode (
1976              MAC_ENTRY_LABEL,
1977              &StartOpCodeHandle,
1978              &StartLabel,
1979              &EndOpCodeHandle,
1980              &EndLabel
1981              );
1982   if (EFI_ERROR (Status)) {
1983     return Status;
1984   }
1985 
1986   //
1987   // Ask user to select a MAC for this attempt.
1988   //
1989   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
1990     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
1991     IScsiMacAddrToStr (
1992       &NicInfo->PermanentAddress,
1993       NicInfo->HwAddressSize,
1994       NicInfo->VlanId,
1995       MacString
1996       );
1997 
1998     UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"MAC %s", MacString);
1999     PortTitleToken = HiiSetString (
2000                        mCallbackInfo->RegisteredHandle,
2001                        0,
2002                        mPrivate->PortString,
2003                        NULL
2004                        );
2005     if (PortTitleToken == 0) {
2006       Status = EFI_INVALID_PARAMETER;
2007       goto Exit;
2008     }
2009 
2010     UnicodeSPrint (
2011       mPrivate->PortString,
2012       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2013       L"PFA: Bus %d | Dev %d | Func %d",
2014       NicInfo->BusNumber,
2015       NicInfo->DeviceNumber,
2016       NicInfo->FunctionNumber
2017       );
2018     PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, mPrivate->PortString, NULL);
2019     if (PortTitleHelpToken == 0) {
2020       Status = EFI_INVALID_PARAMETER;
2021       goto Exit;
2022     }
2023 
2024     HiiCreateGotoOpCode (
2025       StartOpCodeHandle,                      // Container for dynamic created opcodes
2026       FORMID_ATTEMPT_FORM,
2027       PortTitleToken,
2028       PortTitleHelpToken,
2029       EFI_IFR_FLAG_CALLBACK,                  // Question flag
2030       (UINT16) (KEY_MAC_ENTRY_BASE + NicInfo->NicIndex)
2031       );
2032   }
2033 
2034   Status = HiiUpdateForm (
2035              mCallbackInfo->RegisteredHandle, // HII handle
2036              &gIScsiConfigGuid,               // Formset GUID
2037              FORMID_MAC_FORM,                 // Form ID
2038              StartOpCodeHandle,               // Label for where to insert opcodes
2039              EndOpCodeHandle                  // Replace data
2040              );
2041 
2042 Exit:
2043   HiiFreeOpCodeHandle (StartOpCodeHandle);
2044   HiiFreeOpCodeHandle (EndOpCodeHandle);
2045 
2046   return Status;
2047 }
2048 
2049 /**
2050   Add the attempts by keyword 'iSCSIAddAttempts', you can use this keyword with
2051   value 'attempt:1 attempt:2' etc to add one or more attempts once. This is different
2052   with IScsiConfigAddAttempt function which is used to add attempt by UI configuration.
2053 
2054   @param[in]  AttemptList        The new attempt List will be added.
2055 
2056   @retval EFI_SUCCESS            The operation to add attempt list successfully.
2057   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
2058   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
2059   @retval EFI_OUT_OF_RESOURCES   Fail to finish the operation due to lack of
2060                                  resources.
2061 
2062 **/
2063 EFI_STATUS
IScsiConfigAddAttemptsByKeywords(IN UINT8 * AttemptList)2064 IScsiConfigAddAttemptsByKeywords (
2065   IN UINT8                   *AttemptList
2066   )
2067 {
2068   UINT8                       Index;
2069   UINT8                       Number;
2070   UINTN                       TotalNumber;
2071   UINT8                       Nic;
2072   UINT8                       *AttemptConfigOrder;
2073   UINTN                       AttemptConfigOrderSize;
2074   UINT8                       *AttemptConfigOrderTmp;
2075   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2076   ISCSI_NIC_INFO              *NicInfo;
2077   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
2078   CHAR16                      IScsiMode[64];
2079   CHAR16                      IpMode[64];
2080   EFI_STATUS                  Status;
2081 
2082   Nic = mPrivate->CurrentNic;
2083   NicInfo = IScsiGetNicInfoByIndex (Nic);
2084   if (NicInfo == NULL) {
2085     return EFI_NOT_FOUND;
2086   }
2087 
2088   //
2089   // The MAC info will be recorded in Config Data.
2090   //
2091   IScsiMacAddrToStr (
2092     &NicInfo->PermanentAddress,
2093     NicInfo->HwAddressSize,
2094     NicInfo->VlanId,
2095     MacString
2096     );
2097 
2098   for (Index = 0; Index < PcdGet8 (PcdMaxIScsiAttemptNumber); Index++) {
2099     if (AttemptList[Index] == 0) {
2100       continue;
2101     }
2102 
2103     //
2104     // Add the attempt.
2105     //
2106     Number = AttemptList[Index];
2107 
2108     UnicodeSPrint (
2109       mPrivate->PortString,
2110       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2111       L"Attempt %d",
2112       Number
2113       );
2114 
2115     GetVariable2 (
2116            mPrivate->PortString,
2117            &gEfiIScsiInitiatorNameProtocolGuid,
2118            (VOID**)&AttemptConfigData,
2119            NULL
2120            );
2121     if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) {
2122       return EFI_INVALID_PARAMETER;
2123     }
2124 
2125     AttemptConfigData->Actived = ISCSI_ACTIVE_ENABLED;
2126     AttemptConfigData->NicIndex = NicInfo->NicIndex;
2127     UnicodeStrToAsciiStrS (MacString, AttemptConfigData->MacString, ISCSI_MAX_MAC_STRING_LEN);
2128 
2129     //
2130     // Generate OUI-format ISID based on MAC address.
2131     //
2132     CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6);
2133     AttemptConfigData->SessionConfigData.IsId[0] =
2134       (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F);
2135 
2136     //
2137     // Configure the iSCSI Mode and IpMode to default.
2138     // Add Attempt Help Info.
2139     //
2140     UnicodeSPrint (IScsiMode, 64, L"Disabled");
2141     UnicodeSPrint (IpMode, 64, L"IP4");
2142     UnicodeSPrint (
2143       mPrivate->PortString,
2144       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2145       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
2146       MacString,
2147       NicInfo->BusNumber,
2148       NicInfo->DeviceNumber,
2149       NicInfo->FunctionNumber,
2150       IScsiMode,
2151       IpMode
2152       );
2153 
2154     AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
2155                                                  mCallbackInfo->RegisteredHandle,
2156                                                  0,
2157                                                  mPrivate->PortString,
2158                                                  NULL
2159                                                  );
2160     if (AttemptConfigData->AttemptTitleHelpToken == 0) {
2161       return EFI_OUT_OF_RESOURCES;
2162     }
2163 
2164     //
2165     // Get current Attempt order and number.
2166     //
2167     AttemptConfigOrder = IScsiGetVariableAndSize (
2168                            L"AttemptOrder",
2169                            &gIScsiConfigGuid,
2170                            &AttemptConfigOrderSize
2171                            );
2172     TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);
2173     TotalNumber++;
2174 
2175     //
2176     // Append the new created attempt order to the end.
2177     //
2178     AttemptConfigOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8));
2179     if (AttemptConfigOrderTmp == NULL) {
2180       if (AttemptConfigOrder != NULL) {
2181         FreePool (AttemptConfigOrder);
2182       }
2183       return EFI_OUT_OF_RESOURCES;
2184     }
2185     if (AttemptConfigOrder != NULL) {
2186       CopyMem (AttemptConfigOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize);
2187       FreePool (AttemptConfigOrder);
2188     }
2189 
2190     AttemptConfigOrderTmp[TotalNumber - 1] = Number;
2191     AttemptConfigOrder               = AttemptConfigOrderTmp;
2192     AttemptConfigOrderSize           = TotalNumber * sizeof (UINT8);
2193 
2194     Status = gRT->SetVariable (
2195                     L"AttemptOrder",
2196                     &gIScsiConfigGuid,
2197                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2198                     AttemptConfigOrderSize,
2199                     AttemptConfigOrder
2200                     );
2201     FreePool (AttemptConfigOrder);
2202     if (EFI_ERROR (Status)) {
2203       return Status;
2204     }
2205 
2206     //
2207     // Record the attempt in global link list.
2208     //
2209     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
2210     mPrivate->AttemptCount++;
2211     UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Attempt %d", AttemptConfigData->AttemptConfigIndex);
2212     gRT->SetVariable (
2213            mPrivate->PortString,
2214            &gEfiIScsiInitiatorNameProtocolGuid,
2215            ISCSI_CONFIG_VAR_ATTR,
2216            sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
2217            AttemptConfigData
2218            );
2219 
2220   }
2221 
2222   return EFI_SUCCESS;
2223 }
2224 
2225 /**
2226   Callback function when user presses "Commit Changes and Exit" in Delete Attempts or Delete Attempts by Keyword.
2227 
2228   @param[in]  IfrNvData          The IFR NV data.
2229 
2230   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
2231   @retval EFI_SUCCESS            The operation is completed successfully.
2232   @retval EFI_ABOTRED            This operation is aborted cause of error
2233                                  configuration.
2234   @retval EFI_OUT_OF_RESOURCES   Fail to finish the operation due to lack of
2235                                  resources.
2236 
2237 **/
2238 EFI_STATUS
IScsiConfigDeleteAttempts(IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData)2239 IScsiConfigDeleteAttempts (
2240   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
2241   )
2242 {
2243   EFI_STATUS                    Status;
2244   UINTN                         Index;
2245   UINTN                         NewIndex;
2246   ISCSI_ATTEMPT_CONFIG_NVDATA   *AttemptConfigData;
2247   UINT8                         *AttemptConfigOrder;
2248   UINTN                         AttemptConfigOrderSize;
2249   UINT8                         *AttemptNewOrder;
2250   UINT8                         AttemptConfigIndex;
2251   UINT32                        Attribute;
2252   UINTN                         Total;
2253   UINTN                         NewTotal;
2254   LIST_ENTRY                    *Entry;
2255   LIST_ENTRY                    *NextEntry;
2256   ISCSI_SESSION_CONFIG_NVDATA   *ConfigData;
2257 
2258   Index     = 0;
2259 
2260   AttemptConfigOrder = IScsiGetVariableAndSize (
2261                          L"AttemptOrder",
2262                          &gIScsiConfigGuid,
2263                          &AttemptConfigOrderSize
2264                          );
2265   if ((AttemptConfigOrder == NULL) || (AttemptConfigOrderSize == 0)) {
2266     return EFI_NOT_FOUND;
2267   }
2268 
2269   AttemptNewOrder = AllocateZeroPool (AttemptConfigOrderSize);
2270   if (AttemptNewOrder == NULL) {
2271     Status = EFI_OUT_OF_RESOURCES;
2272     goto Error;
2273   }
2274 
2275   Total    = AttemptConfigOrderSize / sizeof (UINT8);
2276   NewTotal = Total;
2277 
2278   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
2279     if (IfrNvData->DeleteAttemptList[Index] == 0) {
2280       Index++;
2281       continue;
2282     }
2283 
2284     //
2285     // Delete the attempt.
2286     //
2287 
2288     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
2289 
2290     //
2291     // Remove this attempt from UI configured attempt list.
2292     //
2293     RemoveEntryList (&AttemptConfigData->Link);
2294     mPrivate->AttemptCount--;
2295 
2296     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
2297       if (mPrivate->MpioCount < 1) {
2298         Status = EFI_ABORTED;
2299         goto Error;
2300       }
2301 
2302       //
2303       // No more attempt is enabled for MPIO. Transit the iSCSI mode to single path.
2304       //
2305       if (--mPrivate->MpioCount == 0) {
2306         mPrivate->EnableMpio = FALSE;
2307       }
2308     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
2309       if (mPrivate->SinglePathCount < 1) {
2310         Status = EFI_ABORTED;
2311         goto Error;
2312       }
2313 
2314       mPrivate->SinglePathCount--;
2315     }
2316 
2317     AttemptConfigIndex = AttemptConfigData->AttemptConfigIndex;
2318     FreePool (AttemptConfigData);
2319 
2320     //
2321     // Create a new Attempt
2322     //
2323     AttemptConfigData = AllocateZeroPool (sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA));
2324     if (AttemptConfigData == NULL) {
2325       return EFI_OUT_OF_RESOURCES;
2326     }
2327     ConfigData                    = &AttemptConfigData->SessionConfigData;
2328     ConfigData->TargetPort        = ISCSI_WELL_KNOWN_PORT;
2329     ConfigData->ConnectTimeout    = CONNECT_DEFAULT_TIMEOUT;
2330     ConfigData->ConnectRetryCount = CONNECT_MIN_RETRY;
2331 
2332     AttemptConfigData->AuthenticationType           = ISCSI_AUTH_TYPE_CHAP;
2333     AttemptConfigData->AuthConfigData.CHAP.CHAPType = ISCSI_CHAP_UNI;
2334     //
2335     // Configure the Attempt index and set variable.
2336     //
2337     AttemptConfigData->AttemptConfigIndex = AttemptConfigIndex;
2338 
2339     //
2340     // Set the attempt name to default.
2341     //
2342     UnicodeSPrint (
2343       mPrivate->PortString,
2344       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2345       L"Attempt %d",
2346       (UINTN) AttemptConfigData->AttemptConfigIndex
2347       );
2348     UnicodeStrToAsciiStrS (mPrivate->PortString, AttemptConfigData->AttemptName, ATTEMPT_NAME_SIZE);
2349     gRT->SetVariable (
2350            mPrivate->PortString,
2351            &gEfiIScsiInitiatorNameProtocolGuid,
2352            ISCSI_CONFIG_VAR_ATTR,
2353            sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
2354            AttemptConfigData
2355            );
2356 
2357     //
2358     // Mark the attempt order in NVR to be deleted - 0.
2359     //
2360     for (NewIndex = 0; NewIndex < Total; NewIndex++) {
2361       if (AttemptConfigOrder[NewIndex] == AttemptConfigData->AttemptConfigIndex) {
2362         AttemptConfigOrder[NewIndex] = 0;
2363         break;
2364       }
2365     }
2366 
2367     NewTotal--;
2368     if (mCallbackInfo->Current == AttemptConfigData) {
2369       mCallbackInfo->Current = NULL;
2370     }
2371     FreePool (AttemptConfigData);
2372 
2373     //
2374     // Check next Attempt.
2375     //
2376     Index++;
2377   }
2378 
2379   //
2380   // Construct AttemptNewOrder.
2381   //
2382   for (Index = 0, NewIndex = 0; Index < Total; Index++) {
2383     if (AttemptConfigOrder[Index] != 0) {
2384       AttemptNewOrder[NewIndex] = AttemptConfigOrder[Index];
2385       NewIndex++;
2386     }
2387   }
2388 
2389   Attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE;
2390 
2391   //
2392   // Update AttemptOrder in NVR.
2393   //
2394   Status = gRT->SetVariable (
2395                   L"AttemptOrder",
2396                   &gIScsiConfigGuid,
2397                   Attribute,
2398                   NewTotal * sizeof (UINT8),
2399                   AttemptNewOrder
2400                   );
2401 
2402 Error:
2403   if (AttemptConfigOrder != NULL) {
2404     FreePool (AttemptConfigOrder);
2405   }
2406 
2407   if (AttemptNewOrder != NULL) {
2408     FreePool (AttemptNewOrder);
2409   }
2410 
2411   return Status;
2412 }
2413 
2414 
2415 /**
2416   Callback function when user presses "Delete Attempts".
2417 
2418   @param[in]  IfrNvData          The IFR nv data.
2419 
2420   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
2421   @retval EFI_BUFFER_TOO_SMALL   The buffer in UpdateData is too small.
2422   @retval EFI_SUCCESS            The operation is completed successfully.
2423 
2424 **/
2425 EFI_STATUS
IScsiConfigDisplayDeleteAttempts(IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData)2426 IScsiConfigDisplayDeleteAttempts (
2427   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
2428   )
2429 {
2430 
2431   UINT8                       *AttemptConfigOrder;
2432   UINTN                       AttemptConfigOrderSize;
2433   LIST_ENTRY                  *Entry;
2434   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2435   UINT8                       Index;
2436   VOID                        *StartOpCodeHandle;
2437   EFI_IFR_GUID_LABEL          *StartLabel;
2438   VOID                        *EndOpCodeHandle;
2439   EFI_IFR_GUID_LABEL          *EndLabel;
2440   EFI_STATUS                  Status;
2441 
2442   Status = IScsiCreateOpCode (
2443              DELETE_ENTRY_LABEL,
2444              &StartOpCodeHandle,
2445              &StartLabel,
2446              &EndOpCodeHandle,
2447              &EndLabel
2448              );
2449   if (EFI_ERROR (Status)) {
2450     return Status;
2451   }
2452 
2453   AttemptConfigOrder = IScsiGetVariableAndSize (
2454                          L"AttemptOrder",
2455                          &gIScsiConfigGuid,
2456                          &AttemptConfigOrderSize
2457                          );
2458   if (AttemptConfigOrder != NULL) {
2459     //
2460     // Create the check box opcode to be deleted.
2461     //
2462     Index = 0;
2463 
2464     NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
2465       AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
2466       IfrNvData->DeleteAttemptList[Index] = 0x00;
2467 
2468       HiiCreateCheckBoxOpCode(
2469         StartOpCodeHandle,
2470         (EFI_QUESTION_ID) (ATTEMPT_DEL_QUESTION_ID + Index),
2471         CONFIGURATION_VARSTORE_ID,
2472         (UINT16) (ATTEMPT_DEL_VAR_OFFSET + Index),
2473         AttemptConfigData->AttemptTitleToken,
2474         AttemptConfigData->AttemptTitleHelpToken,
2475         0,
2476         0,
2477         NULL
2478         );
2479 
2480       Index++;
2481 
2482       if (Index == ISCSI_MAX_ATTEMPTS_NUM) {
2483         break;
2484       }
2485     }
2486 
2487     FreePool (AttemptConfigOrder);
2488   }
2489 
2490   Status = HiiUpdateForm (
2491              mCallbackInfo->RegisteredHandle, // HII handle
2492              &gIScsiConfigGuid,               // Formset GUID
2493              FORMID_DELETE_FORM,              // Form ID
2494              StartOpCodeHandle,               // Label for where to insert opcodes
2495              EndOpCodeHandle                  // Replace data
2496              );
2497 
2498   HiiFreeOpCodeHandle (StartOpCodeHandle);
2499   HiiFreeOpCodeHandle (EndOpCodeHandle);
2500 
2501   return Status;
2502 }
2503 
2504 
2505 /**
2506   Callback function when user presses "Change Attempt Order".
2507 
2508   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
2509   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
2510                                  operation.
2511   @retval EFI_SUCCESS            The operation is completed successfully.
2512 
2513 **/
2514 EFI_STATUS
IScsiConfigDisplayOrderAttempts(VOID)2515 IScsiConfigDisplayOrderAttempts (
2516   VOID
2517   )
2518 {
2519   EFI_STATUS                  Status;
2520   UINT8                       Index;
2521   LIST_ENTRY                  *Entry;
2522   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2523   VOID                        *StartOpCodeHandle;
2524   EFI_IFR_GUID_LABEL          *StartLabel;
2525   VOID                        *EndOpCodeHandle;
2526   EFI_IFR_GUID_LABEL          *EndLabel;
2527   VOID                        *OptionsOpCodeHandle;
2528 
2529   Status = IScsiCreateOpCode (
2530              ORDER_ENTRY_LABEL,
2531              &StartOpCodeHandle,
2532              &StartLabel,
2533              &EndOpCodeHandle,
2534              &EndLabel
2535              );
2536   if (EFI_ERROR (Status)) {
2537     return Status;
2538   }
2539   ASSERT (StartOpCodeHandle != NULL);
2540 
2541   OptionsOpCodeHandle = NULL;
2542 
2543   //
2544   // If no attempt to be ordered, update the original form and exit.
2545   //
2546   if (mPrivate->AttemptCount == 0) {
2547     goto Exit;
2548   }
2549 
2550   //
2551   // Create Option OpCode.
2552   //
2553   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
2554   if (OptionsOpCodeHandle == NULL) {
2555     Status = EFI_OUT_OF_RESOURCES;
2556     goto Error;
2557   }
2558 
2559   Index = 0;
2560 
2561   NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
2562     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
2563     HiiCreateOneOfOptionOpCode (
2564       OptionsOpCodeHandle,
2565       AttemptConfigData->AttemptTitleToken,
2566       0,
2567       EFI_IFR_NUMERIC_SIZE_1,
2568       AttemptConfigData->AttemptConfigIndex
2569       );
2570     Index++;
2571   }
2572 
2573   ASSERT (Index == mPrivate->AttemptCount);
2574 
2575   HiiCreateOrderedListOpCode (
2576     StartOpCodeHandle,                          // Container for dynamic created opcodes
2577     DYNAMIC_ORDERED_LIST_QUESTION_ID,           // Question ID
2578     CONFIGURATION_VARSTORE_ID,                  // VarStore ID
2579     DYNAMIC_ORDERED_LIST_VAR_OFFSET,            // Offset in Buffer Storage
2580     STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),     // Question prompt text
2581     STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),     // Question help text
2582     0,                                          // Question flag
2583     EFI_IFR_UNIQUE_SET,                         // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET
2584     EFI_IFR_NUMERIC_SIZE_1,                     // Data type of Question value
2585     ISCSI_MAX_ATTEMPTS_NUM,                     // Maximum container
2586     OptionsOpCodeHandle,                        // Option Opcode list
2587     NULL                                        // Default Opcode is NULL
2588     );
2589 
2590 Exit:
2591   Status = HiiUpdateForm (
2592              mCallbackInfo->RegisteredHandle, // HII handle
2593              &gIScsiConfigGuid,               // Formset GUID
2594              FORMID_ORDER_FORM,               // Form ID
2595              StartOpCodeHandle,               // Label for where to insert opcodes
2596              EndOpCodeHandle                  // Replace data
2597              );
2598 
2599 Error:
2600   HiiFreeOpCodeHandle (StartOpCodeHandle);
2601   HiiFreeOpCodeHandle (EndOpCodeHandle);
2602   if (OptionsOpCodeHandle != NULL) {
2603     HiiFreeOpCodeHandle (OptionsOpCodeHandle);
2604   }
2605 
2606   return Status;
2607 }
2608 
2609 /**
2610   Callback function when user presses "Commit Changes and Exit" in Change Attempt Order or Change Attempt Order by Keyword.
2611 
2612   @param[in]  IfrNvData          The IFR nv data.
2613 
2614   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
2615                                  operation.
2616   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
2617   @retval EFI_SUCCESS            The operation is completed successfully.
2618 
2619 **/
2620 EFI_STATUS
IScsiConfigOrderAttempts(IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData)2621 IScsiConfigOrderAttempts (
2622   IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData
2623   )
2624 {
2625   EFI_STATUS                  Status;
2626   UINTN                       Index;
2627   UINTN                       Indexj;
2628   UINT8                       AttemptConfigIndex;
2629   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2630   UINT8                       *AttemptConfigOrder;
2631   UINT8                       *AttemptConfigOrderTmp;
2632   UINTN                       AttemptConfigOrderSize;
2633 
2634   AttemptConfigOrder = IScsiGetVariableAndSize (
2635                          L"AttemptOrder",
2636                          &gIScsiConfigGuid,
2637                          &AttemptConfigOrderSize
2638                          );
2639   if (AttemptConfigOrder == NULL) {
2640     return EFI_NOT_FOUND;
2641   }
2642 
2643   AttemptConfigOrderTmp = AllocateZeroPool (AttemptConfigOrderSize);
2644   if (AttemptConfigOrderTmp == NULL) {
2645     Status = EFI_OUT_OF_RESOURCES;
2646     goto Exit;
2647   }
2648 
2649   for (Index = 0; Index < ISCSI_MAX_ATTEMPTS_NUM; Index++) {
2650     //
2651     // The real content ends with 0.
2652     //
2653     if (IfrNvData->DynamicOrderedList[Index] == 0) {
2654       break;
2655     }
2656 
2657     AttemptConfigIndex = IfrNvData->DynamicOrderedList[Index];
2658     AttemptConfigData  = IScsiConfigGetAttemptByConfigIndex (AttemptConfigIndex);
2659     if (AttemptConfigData == NULL) {
2660       Status = EFI_NOT_FOUND;
2661       goto Exit;
2662     }
2663 
2664     //
2665     // Reorder the Attempt List.
2666     //
2667     RemoveEntryList (&AttemptConfigData->Link);
2668     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
2669 
2670     AttemptConfigOrderTmp[Index] = AttemptConfigIndex;
2671 
2672     //
2673     // Mark it to be deleted - 0.
2674     //
2675     for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {
2676       if (AttemptConfigOrder[Indexj] == AttemptConfigIndex) {
2677         AttemptConfigOrder[Indexj] = 0;
2678         break;
2679       }
2680     }
2681   }
2682 
2683   //
2684   // Adjust the attempt order in NVR.
2685   //
2686   for (; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
2687     for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {
2688       if (AttemptConfigOrder[Indexj] != 0) {
2689         AttemptConfigOrderTmp[Index] = AttemptConfigOrder[Indexj];
2690         AttemptConfigOrder[Indexj]   = 0;
2691         continue;
2692       }
2693     }
2694   }
2695 
2696   Status = gRT->SetVariable (
2697                   L"AttemptOrder",
2698                   &gIScsiConfigGuid,
2699                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2700                   AttemptConfigOrderSize,
2701                   AttemptConfigOrderTmp
2702                   );
2703 
2704 Exit:
2705   if (AttemptConfigOrderTmp != NULL) {
2706     FreePool (AttemptConfigOrderTmp);
2707   }
2708 
2709   FreePool (AttemptConfigOrder);
2710   return Status;
2711 }
2712 
2713 
2714 /**
2715   Callback function when a user presses "Attempt *" or when a user selects a NIC to
2716   create the new attempt.
2717 
2718   @param[in]  KeyValue           A unique value which is sent to the original
2719                                  exporting driver so that it can identify the type
2720                                  of data to expect.
2721   @param[in]  IfrNvData          The IFR nv data.
2722 
2723   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
2724                                  operation.
2725   @retval EFI_NOT_FOUND          Cannot find the corresponding variable.
2726   @retval EFI_UNSUPPORTED        Can not create more attempts.
2727   @retval EFI_SUCCESS            The operation is completed successfully.
2728 
2729 **/
2730 EFI_STATUS
IScsiConfigProcessDefault(IN EFI_QUESTION_ID KeyValue,IN ISCSI_CONFIG_IFR_NVDATA * IfrNvData)2731 IScsiConfigProcessDefault (
2732   IN  EFI_QUESTION_ID              KeyValue,
2733   IN  ISCSI_CONFIG_IFR_NVDATA      *IfrNvData
2734   )
2735 {
2736   BOOLEAN                     NewAttempt;
2737   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2738   UINT8                       CurrentAttemptConfigIndex;
2739   ISCSI_NIC_INFO              *NicInfo;
2740   UINT8                       NicIndex;
2741   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
2742   UINT8                       *AttemptConfigOrder;
2743   UINTN                       AttemptConfigOrderSize;
2744   UINTN                       Index;
2745   EFI_INPUT_KEY               Key;
2746 
2747   AttemptConfigData = NULL;
2748   //
2749   // Is User creating a new attempt?
2750   //
2751   NewAttempt = FALSE;
2752 
2753   if ((KeyValue >= KEY_MAC_ENTRY_BASE) &&
2754       (KeyValue <= (UINT16) (mPrivate->MaxNic + KEY_MAC_ENTRY_BASE))) {
2755     //
2756     // User has pressed "Add an Attempt" and then selects a NIC.
2757     //
2758     NewAttempt = TRUE;
2759   } else if ((KeyValue >= KEY_ATTEMPT_ENTRY_BASE) &&
2760              (KeyValue < (ISCSI_MAX_ATTEMPTS_NUM + KEY_ATTEMPT_ENTRY_BASE))) {
2761 
2762     //
2763     // User has pressed "Attempt *".
2764     //
2765     NewAttempt = FALSE;
2766   } else {
2767     //
2768     // Don't process anything.
2769     //
2770     return EFI_SUCCESS;
2771   }
2772 
2773   if (NewAttempt) {
2774     //
2775     // Determine which NIC user has selected for the new created attempt.
2776     //
2777     NicIndex = (UINT8) (KeyValue - KEY_MAC_ENTRY_BASE);
2778     NicInfo = IScsiGetNicInfoByIndex (NicIndex);
2779     if (NicInfo == NULL) {
2780       return EFI_NOT_FOUND;
2781     }
2782 
2783     //
2784     // Create an attempt following the initialized attempt order.
2785     //
2786     AttemptConfigOrder = IScsiGetVariableAndSize (
2787                            L"InitialAttemptOrder",
2788                            &gIScsiConfigGuid,
2789                            &AttemptConfigOrderSize
2790                            );
2791 
2792     if (AttemptConfigOrder == NULL) {
2793       return EFI_NOT_FOUND;
2794     }
2795 
2796     for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
2797       UnicodeSPrint (
2798         mPrivate->PortString,
2799         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2800         L"Attempt %d",
2801         (UINTN) AttemptConfigOrder[Index]
2802         );
2803       GetVariable2 (
2804                    mPrivate->PortString,
2805                    &gEfiIScsiInitiatorNameProtocolGuid,
2806                    (VOID**)&AttemptConfigData,
2807                    NULL
2808                    );
2809       if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_ENABLED) {
2810         continue;
2811       }
2812 
2813       break;
2814     }
2815 
2816     if (Index > PcdGet8 (PcdMaxIScsiAttemptNumber)) {
2817       CreatePopUp (
2818         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
2819         &Key,
2820         L"Can not create more attempts, Please configure the PcdMaxIScsiAttemptNumber if needed!",
2821         NULL
2822         );
2823       return EFI_UNSUPPORTED;
2824     }
2825 
2826     if (AttemptConfigOrder != NULL) {
2827       FreePool (AttemptConfigOrder);
2828     }
2829 
2830     //
2831     // Record the MAC info in Config Data.
2832     //
2833     IScsiMacAddrToStr (
2834       &NicInfo->PermanentAddress,
2835       NicInfo->HwAddressSize,
2836       NicInfo->VlanId,
2837       MacString
2838       );
2839 
2840     ASSERT (AttemptConfigData != NULL);
2841     UnicodeStrToAsciiStrS (MacString, AttemptConfigData->MacString, sizeof (AttemptConfigData->MacString));
2842     AttemptConfigData->NicIndex = NicIndex;
2843     AttemptConfigData->Actived = ISCSI_ACTIVE_ENABLED;
2844 
2845     //
2846     // Generate OUI-format ISID based on MAC address.
2847     //
2848     CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6);
2849     AttemptConfigData->SessionConfigData.IsId[0] =
2850       (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F);
2851 
2852     //
2853     // Add the help info for the new attempt.
2854     //
2855     UnicodeSPrint (
2856       mPrivate->PortString,
2857       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2858       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d",
2859       MacString,
2860       NicInfo->BusNumber,
2861       NicInfo->DeviceNumber,
2862       NicInfo->FunctionNumber
2863       );
2864 
2865     AttemptConfigData->AttemptTitleHelpToken  = HiiSetString (
2866                                                   mCallbackInfo->RegisteredHandle,
2867                                                   0,
2868                                                   mPrivate->PortString,
2869                                                   NULL
2870                                                   );
2871     if (AttemptConfigData->AttemptTitleHelpToken == 0) {
2872       FreePool (AttemptConfigData);
2873       return EFI_OUT_OF_RESOURCES;
2874     }
2875 
2876   } else {
2877     //
2878     // Determine which Attempt user has selected to configure.
2879     // Get the attempt configuration data.
2880     //
2881     CurrentAttemptConfigIndex = (UINT8) (KeyValue - KEY_ATTEMPT_ENTRY_BASE);
2882 
2883     AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (CurrentAttemptConfigIndex);
2884     if (AttemptConfigData == NULL) {
2885       DEBUG ((DEBUG_ERROR, "Corresponding configuration data can not be retrieved!\n"));
2886       return EFI_NOT_FOUND;
2887     }
2888   }
2889 
2890   //
2891   // Clear the old IFR data to avoid sharing it with other attempts.
2892   //
2893   if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
2894     ZeroMem (IfrNvData->CHAPName, sizeof (IfrNvData->CHAPName));
2895     ZeroMem (IfrNvData->CHAPSecret, sizeof (IfrNvData->CHAPSecret));
2896     ZeroMem (IfrNvData->ReverseCHAPName, sizeof (IfrNvData->ReverseCHAPName));
2897     ZeroMem (IfrNvData->ReverseCHAPSecret, sizeof (IfrNvData->ReverseCHAPSecret));
2898   }
2899 
2900   IScsiConvertAttemptConfigDataToIfrNvData (AttemptConfigData, IfrNvData);
2901 
2902   //
2903   // Update current attempt to be a new created attempt or an existing attempt.
2904   //
2905   mCallbackInfo->Current = AttemptConfigData;
2906 
2907   return EFI_SUCCESS;
2908 }
2909 
2910 
2911 /**
2912 
2913   This function allows the caller to request the current
2914   configuration for one or more named elements. The resulting
2915   string is in <ConfigAltResp> format. Also, any and all alternative
2916   configuration strings shall be appended to the end of the
2917   current configuration string. If they are, they must appear
2918   after the current configuration. They must contain the same
2919   routing (GUID, NAME, PATH) as the current configuration string.
2920   They must have an additional description indicating the type of
2921   alternative configuration the string represents,
2922   "ALTCFG=<StringToken>". That <StringToken> (when
2923   converted from Hex UNICODE to binary) is a reference to a
2924   string in the associated string pack.
2925 
2926   @param[in]  This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
2927 
2928   @param[in]  Request    A null-terminated Unicode string in
2929                          <ConfigRequest> format. Note that this
2930                          includes the routing information as well as
2931                          the configurable name / value pairs. It is
2932                          invalid for this string to be in
2933                          <MultiConfigRequest> format.
2934 
2935   @param[out] Progress   On return, points to a character in the
2936                          Request string. Points to the string's null
2937                          terminator if request was successful. Points
2938                          to the most recent "&" before the first
2939                          failing name / value pair (or the beginning
2940                          of the string if the failure is in the first
2941                          name / value pair) if the request was not successful.
2942 
2943   @param[out] Results    A null-terminated Unicode string in
2944                          <ConfigAltResp> format which has all values
2945                          filled in for the names in the Request string.
2946                          String to be allocated by the called function.
2947 
2948   @retval EFI_SUCCESS             The Results string is filled with the
2949                                   values corresponding to all requested
2950                                   names.
2951 
2952   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
2953                                   parts of the results that must be
2954                                   stored awaiting possible future
2955                                   protocols.
2956 
2957   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL
2958                                   for the Request parameter
2959                                   would result in this type of
2960                                   error. In this case, the
2961                                   Progress parameter would be
2962                                   set to NULL.
2963 
2964   @retval EFI_NOT_FOUND           Routing data doesn't match any
2965                                   known driver. Progress set to the
2966                                   first character in the routing header.
2967                                   Note: There is no requirement that the
2968                                   driver validate the routing data. It
2969                                   must skip the <ConfigHdr> in order to
2970                                   process the names.
2971 
2972   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
2973                                   to most recent "&" before the
2974                                   error or the beginning of the
2975                                   string.
2976 
2977   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
2978                                   to the & before the name in
2979                                   question.
2980 
2981 **/
2982 EFI_STATUS
2983 EFIAPI
IScsiFormExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)2984 IScsiFormExtractConfig (
2985   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
2986   IN  CONST EFI_STRING                       Request,
2987   OUT EFI_STRING                             *Progress,
2988   OUT EFI_STRING                             *Results
2989   )
2990 {
2991   EFI_STATUS                       Status;
2992   CHAR8                            *InitiatorName;
2993   UINTN                            BufferSize;
2994   ISCSI_CONFIG_IFR_NVDATA          *IfrNvData;
2995   ISCSI_FORM_CALLBACK_INFO         *Private;
2996   EFI_STRING                       ConfigRequestHdr;
2997   EFI_STRING                       ConfigRequest;
2998   BOOLEAN                          AllocatedRequest;
2999   UINTN                            Size;
3000 
3001   if (This == NULL || Progress == NULL || Results == NULL) {
3002     return EFI_INVALID_PARAMETER;
3003   }
3004 
3005   *Progress = Request;
3006   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gIScsiConfigGuid, mVendorStorageName)) {
3007     return EFI_NOT_FOUND;
3008   }
3009 
3010   ConfigRequestHdr = NULL;
3011   ConfigRequest    = NULL;
3012   AllocatedRequest = FALSE;
3013   Size             = 0;
3014 
3015   Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
3016   IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
3017   if (IfrNvData == NULL) {
3018     return EFI_OUT_OF_RESOURCES;
3019   }
3020 
3021 
3022   if (Private->Current!= NULL) {
3023     IScsiConvertAttemptConfigDataToIfrNvData (Private->Current, IfrNvData);
3024   }
3025 
3026   //
3027   // Extract all AttemptConfigData to Keyword stroage of IfrNvData.
3028   //
3029   IScsiConvertAttemptConfigDataToIfrNvDataByKeyword (IfrNvData);
3030 
3031   BufferSize    = ISCSI_NAME_MAX_SIZE;
3032   InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize);
3033   if (InitiatorName == NULL) {
3034     FreePool (IfrNvData);
3035     return EFI_OUT_OF_RESOURCES;
3036   }
3037 
3038   Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
3039   if (EFI_ERROR (Status)) {
3040     IfrNvData->InitiatorName[0] = L'\0';
3041   } else {
3042     AsciiStrToUnicodeStrS (
3043       InitiatorName,
3044       IfrNvData->InitiatorName,
3045       sizeof (IfrNvData->InitiatorName) / sizeof (IfrNvData->InitiatorName[0])
3046       );
3047   }
3048 
3049   //
3050   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
3051   //
3052   BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
3053   ConfigRequest = Request;
3054   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
3055     //
3056     // Request has no request element, construct full request string.
3057     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
3058     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
3059     //
3060     ConfigRequestHdr = HiiConstructConfigHdr (&gIScsiConfigGuid, mVendorStorageName, Private->DriverHandle);
3061     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
3062     ConfigRequest = AllocateZeroPool (Size);
3063     if (ConfigRequest == NULL) {
3064       FreePool (IfrNvData);
3065       FreePool (InitiatorName);
3066       return EFI_OUT_OF_RESOURCES;
3067     }
3068     AllocatedRequest = TRUE;
3069     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
3070     FreePool (ConfigRequestHdr);
3071   }
3072 
3073   Status = gHiiConfigRouting->BlockToConfig (
3074                                 gHiiConfigRouting,
3075                                 ConfigRequest,
3076                                 (UINT8 *) IfrNvData,
3077                                 BufferSize,
3078                                 Results,
3079                                 Progress
3080                                 );
3081   FreePool (IfrNvData);
3082   FreePool (InitiatorName);
3083 
3084   //
3085   // Free the allocated config request string.
3086   //
3087   if (AllocatedRequest) {
3088     FreePool (ConfigRequest);
3089     ConfigRequest = NULL;
3090   }
3091   //
3092   // Set Progress string to the original request string.
3093   //
3094   if (Request == NULL) {
3095     *Progress = NULL;
3096   } else if (StrStr (Request, L"OFFSET") == NULL) {
3097     *Progress = Request + StrLen (Request);
3098   }
3099 
3100   return Status;
3101 }
3102 
3103 
3104 /**
3105 
3106   This function applies changes in a driver's configuration.
3107   Input is a Configuration, which has the routing data for this
3108   driver followed by name / value configuration pairs. The driver
3109   must apply those pairs to its configurable storage. If the
3110   driver's configuration is stored in a linear block of data
3111   and the driver's name / value pairs are in <BlockConfig>
3112   format, it may use the ConfigToBlock helper function (above) to
3113   simplify the job.
3114 
3115   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3116 
3117   @param[in]  Configuration  A null-terminated Unicode string in
3118                              <ConfigString> format.
3119 
3120   @param[out] Progress       A pointer to a string filled in with the
3121                              offset of the most recent '&' before the
3122                              first failing name / value pair (or the
3123                              beginning of the string if the failure
3124                              is in the first name / value pair) or
3125                              the terminating NULL if all was
3126                              successful.
3127 
3128   @retval EFI_SUCCESS             The results have been distributed or are
3129                                   awaiting distribution.
3130 
3131   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
3132                                   parts of the results that must be
3133                                   stored awaiting possible future
3134                                   protocols.
3135 
3136   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
3137                                   Results parameter would result
3138                                   in this type of error.
3139 
3140   @retval EFI_NOT_FOUND           Target for the specified routing data
3141                                   was not found.
3142 
3143 **/
3144 EFI_STATUS
3145 EFIAPI
IScsiFormRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)3146 IScsiFormRouteConfig (
3147   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
3148   IN  CONST EFI_STRING                       Configuration,
3149   OUT EFI_STRING                             *Progress
3150   )
3151 {
3152   EFI_STATUS                       Status;
3153   ISCSI_CONFIG_IFR_NVDATA          *IfrNvData;
3154   ISCSI_ATTEMPT_CONFIG_NVDATA      *AttemptConfigData;
3155   LIST_ENTRY                       *Entry;
3156   LIST_ENTRY                       *NextEntry;
3157   ISCSI_NIC_INFO                   *NicInfo;
3158   EFI_INPUT_KEY                    Key;
3159   CHAR16                           MacString[ISCSI_MAX_MAC_STRING_LEN];
3160   CHAR8                            *InitiatorName;
3161   UINT8                            *AttemptList;
3162   UINTN                            BufferSize;
3163   UINTN                            OffSet;
3164   UINTN                            Index;
3165   UINTN                            Index2;
3166 
3167   Index   = 0;
3168   Index2  = 0;
3169   NicInfo = NULL;
3170   AttemptList = NULL;
3171   Status = EFI_SUCCESS;
3172 
3173   if (This == NULL || Configuration == NULL || Progress == NULL) {
3174     return EFI_INVALID_PARAMETER;
3175   }
3176 
3177   //
3178   // Check routing data in <ConfigHdr>.
3179   // Note: if only one Storage is used, then this checking could be skipped.
3180   //
3181   if (!HiiIsConfigHdrMatch (Configuration, &gIScsiConfigGuid, mVendorStorageName)) {
3182     *Progress = Configuration;
3183     return EFI_NOT_FOUND;
3184   }
3185 
3186   IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
3187   if (IfrNvData == NULL) {
3188     return EFI_OUT_OF_RESOURCES;
3189   }
3190 
3191   BufferSize    = ISCSI_NAME_MAX_SIZE;
3192   InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize);
3193   if (InitiatorName == NULL) {
3194     Status = EFI_OUT_OF_RESOURCES;
3195     goto Exit;
3196   }
3197 
3198   //
3199   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
3200   //
3201   BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
3202   Status = gHiiConfigRouting->ConfigToBlock (
3203                              gHiiConfigRouting,
3204                              Configuration,
3205                              (UINT8 *) IfrNvData,
3206                              &BufferSize,
3207                              Progress
3208                              );
3209   if (EFI_ERROR (Status)) {
3210     goto Exit;
3211   }
3212 
3213   if (IfrNvData->InitiatorName[0] != L'\0') {
3214     UnicodeStrToAsciiStrS (IfrNvData->InitiatorName, InitiatorName, ISCSI_NAME_MAX_SIZE);
3215     BufferSize  = AsciiStrSize (InitiatorName);
3216 
3217     Status      = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, InitiatorName);
3218     if (EFI_ERROR (Status)) {
3219       CreatePopUp (
3220         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3221         &Key,
3222         L"Invalid iSCSI Name!",
3223         NULL
3224         );
3225       goto Exit;
3226     }
3227   } else {
3228     Status = IScsiGetValue (Configuration, L"&OFFSET=", &OffSet);
3229     if (EFI_ERROR (Status)) {
3230       goto Exit;
3231     }
3232 
3233     if (OffSet >= ATTEMPT_MAC_ADDR_VAR_OFFSET) {
3234       Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
3235       if (EFI_ERROR (Status)) {
3236         CreatePopUp (
3237           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3238           &Key,
3239           L"Error: please configure iSCSI initiator name first!",
3240           NULL
3241           );
3242         goto Exit;
3243       }
3244     } else {
3245       goto Exit;
3246     }
3247 
3248     if (IfrNvData->ISCSIAddAttemptList[0] != L'\0') {
3249       Status =IScsiGetAttemptIndexList (IfrNvData->ISCSIAddAttemptList, IfrNvData->AddAttemptList, TRUE);
3250       if (EFI_ERROR (Status)) {
3251           CreatePopUp (
3252             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3253             &Key,
3254             L"Error: The add attempt list is invalid",
3255             NULL
3256             );
3257         goto Exit;
3258       }
3259 
3260       Status = IScsiConfigAddAttemptsByKeywords (IfrNvData->AddAttemptList);
3261       if (EFI_ERROR (Status)) {
3262         goto Exit;
3263       }
3264 
3265     } else if (IfrNvData->ISCSIDeleteAttemptList[0] != L'\0') {
3266       AttemptList =(UINT8 *) AllocateZeroPool ((ISCSI_MAX_ATTEMPTS_NUM + 1) * sizeof (UINT8));
3267       if (AttemptList == NULL) {
3268         Status = EFI_OUT_OF_RESOURCES;
3269         goto Exit;
3270       }
3271       Status = IScsiGetAttemptIndexList (IfrNvData->ISCSIDeleteAttemptList, AttemptList, FALSE);
3272       if (EFI_ERROR (Status)) {
3273           CreatePopUp (
3274             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3275             &Key,
3276             L"Error: The delete attempt list is invalid",
3277             NULL
3278             );
3279         goto Exit;
3280       }
3281 
3282       //
3283       // Mark the attempt which will be delete in the global list.
3284       //
3285       NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
3286         AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
3287         while (AttemptList[Index] != 0) {
3288           if (AttemptConfigData->AttemptConfigIndex == AttemptList[Index]) {
3289             IfrNvData->DeleteAttemptList[Index2] = 1;
3290             break;
3291           }
3292           Index ++;
3293         }
3294         Index2 ++;
3295         Index = 0;
3296       }
3297 
3298       Status = IScsiConfigDeleteAttempts (IfrNvData);
3299       if (EFI_ERROR (Status)) {
3300         goto Exit;
3301       }
3302 
3303       FreePool (AttemptList);
3304 
3305     } else if (IfrNvData->ISCSIAttemptOrder[0] != L'\0') {
3306       Status = IScsiGetAttemptIndexList (IfrNvData->ISCSIAttemptOrder, IfrNvData->DynamicOrderedList, FALSE);
3307       if (EFI_ERROR (Status)) {
3308           CreatePopUp (
3309             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3310             &Key,
3311             L"Error: The new attempt order list is invalid",
3312             NULL
3313             );
3314         goto Exit;
3315       }
3316 
3317       Status = IScsiConfigOrderAttempts (IfrNvData);
3318       if (EFI_ERROR (Status)) {
3319         goto Exit;
3320       }
3321 
3322     } else if (IfrNvData->ISCSIMacAddr[0] != L'\0') {
3323       NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
3324         NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
3325         IScsiMacAddrToStr (
3326         &NicInfo->PermanentAddress,
3327         NicInfo->HwAddressSize,
3328         NicInfo->VlanId,
3329         MacString
3330         );
3331         if (!StrCmp(MacString, IfrNvData->ISCSIMacAddr)) {
3332           mPrivate->CurrentNic = NicInfo->NicIndex;
3333           break;
3334         }
3335       }
3336 
3337       if ((NicInfo == NULL) || (NicInfo->NicIndex == 0)) {
3338         Status = EFI_NOT_FOUND;
3339         goto Exit;
3340       }
3341 
3342     } else {
3343       Status = IScsiConvertlfrNvDataToAttemptConfigDataByKeyword (IfrNvData, OffSet);
3344       if (EFI_ERROR (Status)) {
3345         goto Exit;
3346       }
3347     }
3348   }
3349 
3350   IScsiConfigUpdateAttempt ();
3351 
3352 Exit:
3353   if (InitiatorName != NULL) {
3354     FreePool (InitiatorName);
3355   }
3356 
3357   if (IfrNvData != NULL) {
3358     FreePool (IfrNvData);
3359   }
3360 
3361   return Status;
3362 }
3363 
3364 /**
3365 
3366   This function is called to provide results data to the driver.
3367   This data consists of a unique key that is used to identify
3368   which data is either being passed back or being asked for.
3369 
3370   @param[in]       This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3371   @param[in]       Action        Specifies the type of action taken by the browser.
3372   @param[in]       QuestionId    A unique value which is sent to the original
3373                                  exporting driver so that it can identify the type
3374                                  of data to expect. The format of the data tends to
3375                                  vary based on the opcode that generated the callback.
3376   @param[in]       Type          The type of value for the question.
3377   @param[in, out]  Value         A pointer to the data being sent to the original
3378                                  exporting driver.
3379   @param[out]      ActionRequest On return, points to the action requested by the
3380                                  callback function.
3381 
3382   @retval EFI_SUCCESS            The callback successfully handled the action.
3383   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
3384                                  variable and its data.
3385   @retval EFI_DEVICE_ERROR       The variable could not be saved.
3386   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
3387                                  callback.
3388 **/
3389 EFI_STATUS
3390 EFIAPI
IScsiFormCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN OUT EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)3391 IScsiFormCallback (
3392   IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
3393   IN        EFI_BROWSER_ACTION               Action,
3394   IN        EFI_QUESTION_ID                  QuestionId,
3395   IN        UINT8                            Type,
3396   IN OUT    EFI_IFR_TYPE_VALUE               *Value,
3397   OUT       EFI_BROWSER_ACTION_REQUEST       *ActionRequest
3398   )
3399 {
3400   ISCSI_FORM_CALLBACK_INFO    *Private;
3401   UINTN                       BufferSize;
3402   CHAR8                       *IScsiName;
3403   CHAR8                       IpString[ISCSI_NAME_MAX_SIZE];
3404   CHAR8                       LunString[ISCSI_LUN_STR_MAX_LEN];
3405   UINT64                      Lun;
3406   EFI_IP_ADDRESS              HostIp;
3407   EFI_IP_ADDRESS              SubnetMask;
3408   EFI_IP_ADDRESS              Gateway;
3409   ISCSI_CONFIG_IFR_NVDATA     *IfrNvData;
3410   ISCSI_CONFIG_IFR_NVDATA     OldIfrNvData;
3411   EFI_STATUS                  Status;
3412   EFI_INPUT_KEY               Key;
3413   ISCSI_NIC_INFO              *NicInfo;
3414 
3415   NicInfo = NULL;
3416 
3417   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) {
3418     //
3419     // Do nothing for UEFI OPEN/CLOSE Action
3420     //
3421     return EFI_SUCCESS;
3422   }
3423 
3424   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
3425     //
3426     // All other type return unsupported.
3427     //
3428     return EFI_UNSUPPORTED;
3429   }
3430 
3431   if ((Value == NULL) || (ActionRequest == NULL)) {
3432     return EFI_INVALID_PARAMETER;
3433   }
3434 
3435   Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
3436 
3437   //
3438   // Retrieve uncommitted data from Browser
3439   //
3440 
3441   BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
3442   IfrNvData = AllocateZeroPool (BufferSize);
3443   if (IfrNvData == NULL) {
3444     return EFI_OUT_OF_RESOURCES;
3445   }
3446 
3447   IScsiName = (CHAR8 *) AllocateZeroPool (ISCSI_NAME_MAX_SIZE);
3448   if (IScsiName == NULL) {
3449     FreePool (IfrNvData);
3450     return EFI_OUT_OF_RESOURCES;
3451   }
3452 
3453   Status = EFI_SUCCESS;
3454 
3455   ZeroMem (&OldIfrNvData, BufferSize);
3456 
3457   HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);
3458 
3459   CopyMem (&OldIfrNvData, IfrNvData, BufferSize);
3460 
3461   if (Action == EFI_BROWSER_ACTION_CHANGING) {
3462     switch (QuestionId) {
3463     case KEY_ADD_ATTEMPT:
3464       //
3465       // Check whether iSCSI initiator name is configured already.
3466       //
3467       mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
3468       Status = gIScsiInitiatorName.Get (
3469                                      &gIScsiInitiatorName,
3470                                      &mPrivate->InitiatorNameLength,
3471                                      mPrivate->InitiatorName
3472                                      );
3473       if (EFI_ERROR (Status)) {
3474         CreatePopUp (
3475           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3476           &Key,
3477           L"Error: please configure iSCSI initiator name first!",
3478           NULL
3479           );
3480         break;
3481       }
3482 
3483       Status = IScsiConfigAddAttempt ();
3484       break;
3485 
3486     case KEY_DELETE_ATTEMPT:
3487       CopyMem (
3488         OldIfrNvData.DeleteAttemptList,
3489         IfrNvData->DeleteAttemptList,
3490         sizeof (IfrNvData->DeleteAttemptList)
3491         );
3492       Status = IScsiConfigDisplayDeleteAttempts (IfrNvData);
3493       break;
3494 
3495     case KEY_ORDER_ATTEMPT_CONFIG:
3496       //
3497       // Order the attempt according to user input.
3498       //
3499       CopyMem (
3500         OldIfrNvData.DynamicOrderedList,
3501         IfrNvData->DynamicOrderedList,
3502         sizeof (IfrNvData->DynamicOrderedList)
3503         );
3504       IScsiConfigDisplayOrderAttempts ();
3505       break;
3506 
3507     default:
3508       Status = IScsiConfigProcessDefault (QuestionId, IfrNvData);
3509       break;
3510     }
3511   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
3512     switch (QuestionId) {
3513     case KEY_INITIATOR_NAME:
3514       UnicodeStrToAsciiStrS (IfrNvData->InitiatorName, IScsiName, ISCSI_NAME_MAX_SIZE);
3515       BufferSize  = AsciiStrSize (IScsiName);
3516 
3517       Status      = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);
3518       if (EFI_ERROR (Status)) {
3519         CreatePopUp (
3520           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3521           &Key,
3522           L"Invalid iSCSI Name!",
3523           NULL
3524           );
3525       }
3526 
3527       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
3528       break;
3529 
3530     case KEY_SAVE_ATTEMPT_CONFIG:
3531       Status = IScsiConvertIfrNvDataToAttemptConfigData (IfrNvData, Private->Current);
3532       if (EFI_ERROR (Status)) {
3533         break;
3534       }
3535 
3536       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
3537       break;
3538 
3539     case KEY_SAVE_ORDER_CHANGES:
3540       //
3541       // Sync the Attempt Order to NVR.
3542       //
3543       Status = IScsiConfigOrderAttempts (IfrNvData);
3544       if (EFI_ERROR (Status)) {
3545         break;
3546       }
3547 
3548       IScsiConfigUpdateAttempt ();
3549       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
3550       break;
3551 
3552     case KEY_IGNORE_ORDER_CHANGES:
3553       CopyMem (
3554         IfrNvData->DynamicOrderedList,
3555         OldIfrNvData.DynamicOrderedList,
3556         sizeof (IfrNvData->DynamicOrderedList)
3557         );
3558       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
3559       break;
3560 
3561     case KEY_SAVE_DELETE_ATTEMPT:
3562       //
3563       // Delete the Attempt Order from NVR
3564       //
3565       Status = IScsiConfigDeleteAttempts (IfrNvData);
3566       if (EFI_ERROR (Status)) {
3567         break;
3568       }
3569 
3570       IScsiConfigUpdateAttempt ();
3571       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
3572       break;
3573 
3574     case KEY_IGNORE_DELETE_ATTEMPT:
3575       CopyMem (
3576         IfrNvData->DeleteAttemptList,
3577         OldIfrNvData.DeleteAttemptList,
3578         sizeof (IfrNvData->DeleteAttemptList)
3579         );
3580       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
3581       break;
3582 
3583     case KEY_IP_MODE:
3584       switch (Value->u8) {
3585       case IP_MODE_IP6:
3586         NicInfo = IScsiGetNicInfoByIndex (Private->Current->NicIndex);
3587         if(NicInfo == NULL) {
3588           break;
3589         }
3590 
3591         if(!NicInfo->Ipv6Available) {
3592           //
3593           // Current NIC doesn't Support IPv6, hence use IPv4.
3594           //
3595           IfrNvData->IpMode = IP_MODE_IP4;
3596 
3597           CreatePopUp (
3598             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3599             &Key,
3600             L"Current NIC doesn't Support IPv6!",
3601             NULL
3602             );
3603         }
3604 
3605       case IP_MODE_IP4:
3606         ZeroMem (IfrNvData->LocalIp, sizeof (IfrNvData->LocalIp));
3607         ZeroMem (IfrNvData->SubnetMask, sizeof (IfrNvData->SubnetMask));
3608         ZeroMem (IfrNvData->Gateway, sizeof (IfrNvData->Gateway));
3609         ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));
3610         Private->Current->AutoConfigureMode = 0;
3611         ZeroMem (&Private->Current->SessionConfigData.LocalIp, sizeof (EFI_IP_ADDRESS));
3612         ZeroMem (&Private->Current->SessionConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
3613         ZeroMem (&Private->Current->SessionConfigData.Gateway, sizeof (EFI_IP_ADDRESS));
3614         ZeroMem (&Private->Current->SessionConfigData.TargetIp, sizeof (EFI_IP_ADDRESS));
3615 
3616         break;
3617       }
3618 
3619       break;
3620 
3621     case KEY_LOCAL_IP:
3622       Status = NetLibStrToIp4 (IfrNvData->LocalIp, &HostIp.v4);
3623       if (EFI_ERROR (Status) ||
3624           ((Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) &&
3625            !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) {
3626         CreatePopUp (
3627           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3628           &Key,
3629           L"Invalid IP address!",
3630           NULL
3631           );
3632 
3633         Status = EFI_INVALID_PARAMETER;
3634       } else {
3635         CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
3636       }
3637 
3638       break;
3639 
3640     case KEY_SUBNET_MASK:
3641       Status = NetLibStrToIp4 (IfrNvData->SubnetMask, &SubnetMask.v4);
3642       if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
3643         CreatePopUp (
3644           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3645           &Key,
3646           L"Invalid Subnet Mask!",
3647           NULL
3648           );
3649 
3650         Status = EFI_INVALID_PARAMETER;
3651       } else {
3652         CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
3653       }
3654 
3655       break;
3656 
3657     case KEY_GATE_WAY:
3658       Status = NetLibStrToIp4 (IfrNvData->Gateway, &Gateway.v4);
3659       if (EFI_ERROR (Status) ||
3660           ((Gateway.Addr[0] != 0) &&
3661            (Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) &&
3662            !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) {
3663         CreatePopUp (
3664           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3665           &Key,
3666           L"Invalid Gateway!",
3667           NULL
3668           );
3669         Status = EFI_INVALID_PARAMETER;
3670       } else {
3671         CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
3672       }
3673 
3674       break;
3675 
3676     case KEY_TARGET_IP:
3677       UnicodeStrToAsciiStrS (IfrNvData->TargetIp, IpString, sizeof (IpString));
3678       Status = IScsiAsciiStrToIp (IpString, IfrNvData->IpMode, &HostIp);
3679       if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, IfrNvData->IpMode)) {
3680       //
3681       // The target is expressed in URL format or an invalid Ip address, just save.
3682       //
3683       Private->Current->SessionConfigData.DnsMode = TRUE;
3684       ZeroMem (&Private->Current->SessionConfigData.TargetIp, sizeof (Private->Current->SessionConfigData.TargetIp));
3685       UnicodeStrToAsciiStrS (IfrNvData->TargetIp, Private->Current->SessionConfigData.TargetUrl, ISCSI_NAME_MAX_SIZE);
3686       } else {
3687         Private->Current->SessionConfigData.DnsMode = FALSE;
3688         CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp));
3689       }
3690 
3691       break;
3692 
3693     case KEY_TARGET_NAME:
3694       UnicodeStrToAsciiStrS (IfrNvData->TargetName, IScsiName, ISCSI_NAME_MAX_SIZE);
3695       Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
3696       if (EFI_ERROR (Status)) {
3697         CreatePopUp (
3698           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3699           &Key,
3700           L"Invalid iSCSI Name!",
3701           NULL
3702           );
3703       } else {
3704         AsciiStrCpyS (Private->Current->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName);
3705       }
3706 
3707       break;
3708 
3709     case KEY_DHCP_ENABLE:
3710       if (IfrNvData->InitiatorInfoFromDhcp == 0) {
3711         IfrNvData->TargetInfoFromDhcp = 0;
3712       }
3713 
3714       break;
3715 
3716     case KEY_BOOT_LUN:
3717       UnicodeStrToAsciiStrS (IfrNvData->BootLun, LunString, sizeof (LunString));
3718       Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
3719       if (EFI_ERROR (Status)) {
3720         CreatePopUp (
3721           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3722           &Key,
3723           L"Invalid LUN string!",
3724           NULL
3725           );
3726       } else {
3727         CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));
3728       }
3729 
3730       break;
3731 
3732     case KEY_AUTH_TYPE:
3733       switch (Value->u8) {
3734       case ISCSI_AUTH_TYPE_CHAP:
3735         IfrNvData->CHAPType = ISCSI_CHAP_UNI;
3736         break;
3737       default:
3738         break;
3739       }
3740 
3741       break;
3742 
3743     case KEY_CHAP_NAME:
3744       UnicodeStrToAsciiStrS (
3745         IfrNvData->CHAPName,
3746         Private->Current->AuthConfigData.CHAP.CHAPName,
3747         sizeof (Private->Current->AuthConfigData.CHAP.CHAPName)
3748         );
3749       break;
3750 
3751     case KEY_CHAP_SECRET:
3752       UnicodeStrToAsciiStrS (
3753         IfrNvData->CHAPSecret,
3754         Private->Current->AuthConfigData.CHAP.CHAPSecret,
3755         sizeof (Private->Current->AuthConfigData.CHAP.CHAPSecret)
3756         );
3757       break;
3758 
3759     case KEY_REVERSE_CHAP_NAME:
3760       UnicodeStrToAsciiStrS (
3761         IfrNvData->ReverseCHAPName,
3762         Private->Current->AuthConfigData.CHAP.ReverseCHAPName,
3763         sizeof (Private->Current->AuthConfigData.CHAP.ReverseCHAPName)
3764         );
3765       break;
3766 
3767     case KEY_REVERSE_CHAP_SECRET:
3768       UnicodeStrToAsciiStrS (
3769         IfrNvData->ReverseCHAPSecret,
3770         Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret,
3771         sizeof (Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret)
3772         );
3773       break;
3774 
3775     case KEY_CONFIG_ISID:
3776       IScsiParseIsIdFromString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
3777       IScsiConvertIsIdToString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
3778 
3779       break;
3780 
3781     default:
3782       break;
3783     }
3784   }
3785 
3786   if (!EFI_ERROR (Status)) {
3787     //
3788     // Pass changed uncommitted data back to Form Browser.
3789     //
3790     BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
3791     HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
3792   }
3793 
3794   FreePool (IfrNvData);
3795   FreePool (IScsiName);
3796 
3797   return Status;
3798 }
3799 
3800 
3801 /**
3802   Initialize the iSCSI configuration form.
3803 
3804   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
3805 
3806   @retval EFI_SUCCESS             The iSCSI configuration form is initialized.
3807   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
3808 
3809 **/
3810 EFI_STATUS
IScsiConfigFormInit(IN EFI_HANDLE DriverBindingHandle)3811 IScsiConfigFormInit (
3812   IN EFI_HANDLE  DriverBindingHandle
3813   )
3814 {
3815   EFI_STATUS                  Status;
3816   ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;
3817 
3818   CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));
3819   if (CallbackInfo == NULL) {
3820     return EFI_OUT_OF_RESOURCES;
3821   }
3822 
3823   CallbackInfo->Signature   = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
3824   CallbackInfo->Current     = NULL;
3825 
3826   CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
3827   CallbackInfo->ConfigAccess.RouteConfig   = IScsiFormRouteConfig;
3828   CallbackInfo->ConfigAccess.Callback      = IScsiFormCallback;
3829 
3830   //
3831   // Install Device Path Protocol and Config Access protocol to driver handle.
3832   //
3833   Status = gBS->InstallMultipleProtocolInterfaces (
3834                   &CallbackInfo->DriverHandle,
3835                   &gEfiDevicePathProtocolGuid,
3836                   &mIScsiHiiVendorDevicePath,
3837                   &gEfiHiiConfigAccessProtocolGuid,
3838                   &CallbackInfo->ConfigAccess,
3839                   NULL
3840                   );
3841   ASSERT_EFI_ERROR (Status);
3842 
3843   //
3844   // Publish our HII data.
3845   //
3846   CallbackInfo->RegisteredHandle = HiiAddPackages (
3847                                      &gIScsiConfigGuid,
3848                                      CallbackInfo->DriverHandle,
3849                                      IScsiDxeStrings,
3850                                      IScsiConfigVfrBin,
3851                                      NULL
3852                                      );
3853   if (CallbackInfo->RegisteredHandle == NULL) {
3854     gBS->UninstallMultipleProtocolInterfaces (
3855            &CallbackInfo->DriverHandle,
3856            &gEfiDevicePathProtocolGuid,
3857            &mIScsiHiiVendorDevicePath,
3858            &gEfiHiiConfigAccessProtocolGuid,
3859            &CallbackInfo->ConfigAccess,
3860            NULL
3861            );
3862     FreePool(CallbackInfo);
3863     return EFI_OUT_OF_RESOURCES;
3864   }
3865 
3866   mCallbackInfo = CallbackInfo;
3867 
3868   return EFI_SUCCESS;
3869 }
3870 
3871 
3872 /**
3873   Unload the iSCSI configuration form, this includes: delete all the iSCSI
3874   configuration entries, uninstall the form callback protocol, and
3875   free the resources used.
3876 
3877   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
3878 
3879   @retval EFI_SUCCESS             The iSCSI configuration form is unloaded.
3880   @retval Others                  Failed to unload the form.
3881 
3882 **/
3883 EFI_STATUS
IScsiConfigFormUnload(IN EFI_HANDLE DriverBindingHandle)3884 IScsiConfigFormUnload (
3885   IN EFI_HANDLE  DriverBindingHandle
3886   )
3887 {
3888   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
3889   ISCSI_NIC_INFO              *NicInfo;
3890   LIST_ENTRY                  *Entry;
3891   EFI_STATUS                  Status;
3892 
3893   while (!IsListEmpty (&mPrivate->AttemptConfigs)) {
3894     Entry = NetListRemoveHead (&mPrivate->AttemptConfigs);
3895     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
3896     FreePool (AttemptConfigData);
3897     mPrivate->AttemptCount--;
3898   }
3899 
3900   ASSERT (mPrivate->AttemptCount == 0);
3901 
3902   while (!IsListEmpty (&mPrivate->NicInfoList)) {
3903     Entry = NetListRemoveHead (&mPrivate->NicInfoList);
3904     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
3905     FreePool (NicInfo);
3906     mPrivate->NicCount--;
3907   }
3908 
3909   ASSERT (mPrivate->NicCount == 0);
3910 
3911   FreePool (mPrivate);
3912   mPrivate = NULL;
3913 
3914   //
3915   // Remove HII package list.
3916   //
3917   HiiRemovePackages (mCallbackInfo->RegisteredHandle);
3918 
3919   //
3920   // Uninstall Device Path Protocol and Config Access protocol.
3921   //
3922   Status = gBS->UninstallMultipleProtocolInterfaces (
3923                   mCallbackInfo->DriverHandle,
3924                   &gEfiDevicePathProtocolGuid,
3925                   &mIScsiHiiVendorDevicePath,
3926                   &gEfiHiiConfigAccessProtocolGuid,
3927                   &mCallbackInfo->ConfigAccess,
3928                   NULL
3929                   );
3930 
3931   FreePool (mCallbackInfo);
3932 
3933   return Status;
3934 }
3935