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