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