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