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