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