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