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