1 /** @file 2 Miscellaneous routines for iSCSI driver. 3 4 Copyright (c) 2004 - 2016, 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 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef"; 18 19 /** 20 Removes (trims) specified leading and trailing characters from a string. 21 22 @param[in, out] Str Pointer to the null-terminated string to be trimmed. 23 On return, Str will hold the trimmed string. 24 25 @param[in] CharC Character will be trimmed from str. 26 27 **/ 28 VOID 29 IScsiStrTrim ( 30 IN OUT CHAR16 *Str, 31 IN CHAR16 CharC 32 ) 33 { 34 CHAR16 *Pointer1; 35 CHAR16 *Pointer2; 36 37 if (*Str == 0) { 38 return ; 39 } 40 41 // 42 // Trim off the leading and trailing characters c 43 // 44 for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) { 45 ; 46 } 47 48 Pointer2 = Str; 49 if (Pointer2 == Pointer1) { 50 while (*Pointer1 != 0) { 51 Pointer2++; 52 Pointer1++; 53 } 54 } else { 55 while (*Pointer1 != 0) { 56 *Pointer2 = *Pointer1; 57 Pointer1++; 58 Pointer2++; 59 } 60 *Pointer2 = 0; 61 } 62 63 64 for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) { 65 ; 66 } 67 if (Pointer1 != Str + StrLen(Str) - 1) { 68 *(Pointer1 + 1) = 0; 69 } 70 } 71 72 /** 73 Calculate the prefix length of the IPv4 subnet mask. 74 75 @param[in] SubnetMask The IPv4 subnet mask. 76 77 @return The prefix length of the subnet mask. 78 @retval 0 Other errors as indicated. 79 80 **/ 81 UINT8 82 IScsiGetSubnetMaskPrefixLength ( 83 IN EFI_IPv4_ADDRESS *SubnetMask 84 ) 85 { 86 UINT8 Len; 87 UINT32 ReverseMask; 88 89 // 90 // The SubnetMask is in network byte order. 91 // 92 ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]); 93 94 // 95 // Reverse it. 96 // 97 ReverseMask = ~ReverseMask; 98 99 if ((ReverseMask & (ReverseMask + 1)) != 0) { 100 return 0; 101 } 102 103 Len = 0; 104 105 while (ReverseMask != 0) { 106 ReverseMask = ReverseMask >> 1; 107 Len++; 108 } 109 110 return (UINT8) (32 - Len); 111 } 112 113 114 /** 115 Convert the hexadecimal encoded LUN string into the 64-bit LUN. 116 117 @param[in] Str The hexadecimal encoded LUN string. 118 @param[out] Lun Storage to return the 64-bit LUN. 119 120 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun. 121 @retval EFI_INVALID_PARAMETER The string is malformatted. 122 123 **/ 124 EFI_STATUS 125 IScsiAsciiStrToLun ( 126 IN CHAR8 *Str, 127 OUT UINT8 *Lun 128 ) 129 { 130 UINTN Index, IndexValue, IndexNum, SizeStr; 131 CHAR8 TemStr[2]; 132 UINT8 TemValue; 133 UINT16 Value[4]; 134 135 ZeroMem (Lun, 8); 136 ZeroMem (TemStr, 2); 137 ZeroMem ((UINT8 *) Value, sizeof (Value)); 138 SizeStr = AsciiStrLen (Str); 139 IndexValue = 0; 140 IndexNum = 0; 141 142 for (Index = 0; Index < SizeStr; Index ++) { 143 TemStr[0] = Str[Index]; 144 TemValue = (UINT8) AsciiStrHexToUint64 (TemStr); 145 if (TemValue == 0 && TemStr[0] != '0') { 146 if ((TemStr[0] != '-') || (IndexNum == 0)) { 147 // 148 // Invalid Lun Char. 149 // 150 return EFI_INVALID_PARAMETER; 151 } 152 } 153 154 if ((TemValue == 0) && (TemStr[0] == '-')) { 155 // 156 // Next Lun value. 157 // 158 if (++IndexValue >= 4) { 159 // 160 // Max 4 Lun value. 161 // 162 return EFI_INVALID_PARAMETER; 163 } 164 // 165 // Restart str index for the next lun value. 166 // 167 IndexNum = 0; 168 continue; 169 } 170 171 if (++IndexNum > 4) { 172 // 173 // Each Lun Str can't exceed size 4, because it will be as UINT16 value. 174 // 175 return EFI_INVALID_PARAMETER; 176 } 177 178 // 179 // Combine UINT16 value. 180 // 181 Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue); 182 } 183 184 for (Index = 0; Index <= IndexValue; Index ++) { 185 *((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]); 186 } 187 188 return EFI_SUCCESS; 189 } 190 191 /** 192 Convert the 64-bit LUN into the hexadecimal encoded LUN string. 193 194 @param[in] Lun The 64-bit LUN. 195 @param[out] Str The storage to return the hexadecimal encoded LUN string. 196 197 **/ 198 VOID 199 IScsiLunToUnicodeStr ( 200 IN UINT8 *Lun, 201 OUT CHAR16 *Str 202 ) 203 { 204 UINTN Index; 205 CHAR16 *TempStr; 206 207 TempStr = Str; 208 209 for (Index = 0; Index < 4; Index++) { 210 211 if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) { 212 CopyMem (TempStr, L"0-", sizeof (L"0-")); 213 } else { 214 TempStr[0] = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4]; 215 TempStr[1] = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F]; 216 TempStr[2] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4]; 217 TempStr[3] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F]; 218 TempStr[4] = L'-'; 219 TempStr[5] = 0; 220 221 IScsiStrTrim (TempStr, L'0'); 222 } 223 224 TempStr += StrLen (TempStr); 225 } 226 // 227 // Remove the last '-' 228 // 229 ASSERT (StrLen(Str) >= 1); 230 Str[StrLen (Str) - 1] = 0; 231 232 for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) { 233 if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) { 234 Str[Index - 1] = 0; 235 } else { 236 break; 237 } 238 } 239 } 240 241 /** 242 Convert the formatted IP address into the binary IP address. 243 244 @param[in] Str The UNICODE string. 245 @param[in] IpMode Indicates whether the IP address is v4 or v6. 246 @param[out] Ip The storage to return the ASCII string. 247 248 @retval EFI_SUCCESS The binary IP address is returned in Ip. 249 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is 250 invalid. 251 252 **/ 253 EFI_STATUS 254 IScsiAsciiStrToIp ( 255 IN CHAR8 *Str, 256 IN UINT8 IpMode, 257 OUT EFI_IP_ADDRESS *Ip 258 ) 259 { 260 EFI_STATUS Status; 261 262 if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) { 263 return NetLibAsciiStrToIp4 (Str, &Ip->v4); 264 265 } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) { 266 return NetLibAsciiStrToIp6 (Str, &Ip->v6); 267 268 } else if (IpMode == IP_MODE_AUTOCONFIG) { 269 Status = NetLibAsciiStrToIp4 (Str, &Ip->v4); 270 if (!EFI_ERROR (Status)) { 271 return Status; 272 } 273 return NetLibAsciiStrToIp6 (Str, &Ip->v6); 274 275 } 276 277 return EFI_INVALID_PARAMETER; 278 } 279 280 /** 281 Convert the mac address into a hexadecimal encoded "-" seperated string. 282 283 @param[in] Mac The mac address. 284 @param[in] Len Length in bytes of the mac address. 285 @param[in] VlanId VLAN ID of the network device. 286 @param[out] Str The storage to return the mac string. 287 288 **/ 289 VOID 290 IScsiMacAddrToStr ( 291 IN EFI_MAC_ADDRESS *Mac, 292 IN UINT32 Len, 293 IN UINT16 VlanId, 294 OUT CHAR16 *Str 295 ) 296 { 297 UINT32 Index; 298 CHAR16 *String; 299 300 for (Index = 0; Index < Len; Index++) { 301 Str[3 * Index] = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F]; 302 Str[3 * Index + 1] = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F]; 303 Str[3 * Index + 2] = L':'; 304 } 305 306 String = &Str[3 * Index - 1] ; 307 if (VlanId != 0) { 308 String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId); 309 } 310 311 *String = L'\0'; 312 } 313 314 /** 315 Convert the binary encoded buffer into a hexadecimal encoded string. 316 317 @param[in] BinBuffer The buffer containing the binary data. 318 @param[in] BinLength Length of the binary buffer. 319 @param[in, out] HexStr Pointer to the string. 320 @param[in, out] HexLength The length of the string. 321 322 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string 323 and the length of the string is updated. 324 @retval EFI_BUFFER_TOO_SMALL The string is too small. 325 @retval EFI_INVALID_PARAMETER The IP string is malformatted. 326 327 **/ 328 EFI_STATUS 329 IScsiBinToHex ( 330 IN UINT8 *BinBuffer, 331 IN UINT32 BinLength, 332 IN OUT CHAR8 *HexStr, 333 IN OUT UINT32 *HexLength 334 ) 335 { 336 UINTN Index; 337 338 if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) { 339 return EFI_INVALID_PARAMETER; 340 } 341 342 if (((*HexLength) - 3) < BinLength * 2) { 343 *HexLength = BinLength * 2 + 3; 344 return EFI_BUFFER_TOO_SMALL; 345 } 346 347 *HexLength = BinLength * 2 + 3; 348 // 349 // Prefix for Hex String. 350 // 351 HexStr[0] = '0'; 352 HexStr[1] = 'x'; 353 354 for (Index = 0; Index < BinLength; Index++) { 355 HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4]; 356 HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf]; 357 } 358 359 HexStr[Index * 2 + 2] = '\0'; 360 361 return EFI_SUCCESS; 362 } 363 364 365 /** 366 Convert the hexadecimal string into a binary encoded buffer. 367 368 @param[in, out] BinBuffer The binary buffer. 369 @param[in, out] BinLength Length of the binary buffer. 370 @param[in] HexStr The hexadecimal string. 371 372 @retval EFI_SUCCESS The hexadecimal string is converted into a binary 373 encoded buffer. 374 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data. 375 376 **/ 377 EFI_STATUS 378 IScsiHexToBin ( 379 IN OUT UINT8 *BinBuffer, 380 IN OUT UINT32 *BinLength, 381 IN CHAR8 *HexStr 382 ) 383 { 384 UINTN Index; 385 UINTN Length; 386 UINT8 Digit; 387 CHAR8 TemStr[2]; 388 389 ZeroMem (TemStr, sizeof (TemStr)); 390 391 // 392 // Find out how many hex characters the string has. 393 // 394 if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) { 395 HexStr += 2; 396 } 397 398 Length = AsciiStrLen (HexStr); 399 400 for (Index = 0; Index < Length; Index ++) { 401 TemStr[0] = HexStr[Index]; 402 Digit = (UINT8) AsciiStrHexToUint64 (TemStr); 403 if (Digit == 0 && TemStr[0] != '0') { 404 // 405 // Invalid Lun Char. 406 // 407 break; 408 } 409 if ((Index & 1) == 0) { 410 BinBuffer [Index/2] = Digit; 411 } else { 412 BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit); 413 } 414 } 415 416 *BinLength = (UINT32) ((Index + 1)/2); 417 418 return EFI_SUCCESS; 419 } 420 421 422 /** 423 Convert the decimal-constant string or hex-constant string into a numerical value. 424 425 @param[in] Str String in decimal or hex. 426 427 @return The numerical value. 428 429 **/ 430 UINTN 431 IScsiNetNtoi ( 432 IN CHAR8 *Str 433 ) 434 { 435 if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) { 436 Str += 2; 437 438 return AsciiStrHexToUintn (Str); 439 } 440 441 return AsciiStrDecimalToUintn (Str); 442 } 443 444 445 /** 446 Generate random numbers. 447 448 @param[in, out] Rand The buffer to contain random numbers. 449 @param[in] RandLength The length of the Rand buffer. 450 451 **/ 452 VOID 453 IScsiGenRandom ( 454 IN OUT UINT8 *Rand, 455 IN UINTN RandLength 456 ) 457 { 458 UINT32 Random; 459 460 while (RandLength > 0) { 461 Random = NET_RANDOM (NetRandomInitSeed ()); 462 *Rand++ = (UINT8) (Random); 463 RandLength--; 464 } 465 } 466 467 468 /** 469 Record the NIC info in global structure. 470 471 @param[in] Controller The handle of the controller. 472 473 @retval EFI_SUCCESS The operation is completed. 474 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this 475 operation. 476 477 **/ 478 EFI_STATUS 479 IScsiAddNic ( 480 IN EFI_HANDLE Controller 481 ) 482 { 483 EFI_STATUS Status; 484 ISCSI_NIC_INFO *NicInfo; 485 LIST_ENTRY *Entry; 486 EFI_MAC_ADDRESS MacAddr; 487 UINTN HwAddressSize; 488 UINT16 VlanId; 489 490 // 491 // Get MAC address of this network device. 492 // 493 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize); 494 if (EFI_ERROR (Status)) { 495 return Status; 496 } 497 498 // 499 // Get VLAN ID of this network device. 500 // 501 VlanId = NetLibGetVlanId (Controller); 502 503 // 504 // Check whether the NIC info already exists. Return directly if so. 505 // 506 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { 507 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); 508 if (NicInfo->HwAddressSize == HwAddressSize && 509 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 && 510 NicInfo->VlanId == VlanId) { 511 mPrivate->CurrentNic = NicInfo->NicIndex; 512 return EFI_SUCCESS; 513 } 514 515 if (mPrivate->MaxNic < NicInfo->NicIndex) { 516 mPrivate->MaxNic = NicInfo->NicIndex; 517 } 518 } 519 520 // 521 // Record the NIC info in private structure. 522 // 523 NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO)); 524 if (NicInfo == NULL) { 525 return EFI_OUT_OF_RESOURCES; 526 } 527 528 CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize); 529 NicInfo->HwAddressSize = (UINT32) HwAddressSize; 530 NicInfo->VlanId = VlanId; 531 NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1); 532 mPrivate->MaxNic = NicInfo->NicIndex; 533 534 // 535 // Get the PCI location. 536 // 537 IScsiGetNICPciLocation ( 538 Controller, 539 &NicInfo->BusNumber, 540 &NicInfo->DeviceNumber, 541 &NicInfo->FunctionNumber 542 ); 543 544 InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link); 545 mPrivate->NicCount++; 546 547 mPrivate->CurrentNic = NicInfo->NicIndex; 548 return EFI_SUCCESS; 549 } 550 551 552 /** 553 Delete the recorded NIC info from global structure. Also delete corresponding 554 attempts. 555 556 @param[in] Controller The handle of the controller. 557 558 @retval EFI_SUCCESS The operation is completed. 559 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded. 560 561 **/ 562 EFI_STATUS 563 IScsiRemoveNic ( 564 IN EFI_HANDLE Controller 565 ) 566 { 567 EFI_STATUS Status; 568 ISCSI_NIC_INFO *NicInfo; 569 LIST_ENTRY *Entry; 570 LIST_ENTRY *NextEntry; 571 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; 572 ISCSI_NIC_INFO *ThisNic; 573 EFI_MAC_ADDRESS MacAddr; 574 UINTN HwAddressSize; 575 UINT16 VlanId; 576 577 // 578 // Get MAC address of this network device. 579 // 580 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize); 581 if (EFI_ERROR (Status)) { 582 return Status; 583 } 584 585 // 586 // Get VLAN ID of this network device. 587 // 588 VlanId = NetLibGetVlanId (Controller); 589 590 // 591 // Check whether the NIC information exists. 592 // 593 ThisNic = NULL; 594 595 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { 596 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); 597 if (NicInfo->HwAddressSize == HwAddressSize && 598 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 && 599 NicInfo->VlanId == VlanId) { 600 601 ThisNic = NicInfo; 602 break; 603 } 604 } 605 606 if (ThisNic == NULL) { 607 return EFI_NOT_FOUND; 608 } 609 610 mPrivate->CurrentNic = ThisNic->NicIndex; 611 612 RemoveEntryList (&ThisNic->Link); 613 FreePool (ThisNic); 614 mPrivate->NicCount--; 615 616 // 617 // Remove all attempts related to this NIC. 618 // 619 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) { 620 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); 621 if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) { 622 RemoveEntryList (&AttemptConfigData->Link); 623 mPrivate->AttemptCount--; 624 625 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) { 626 if (--mPrivate->MpioCount == 0) { 627 mPrivate->EnableMpio = FALSE; 628 } 629 630 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) { 631 mPrivate->Krb5MpioCount--; 632 } 633 634 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) { 635 mPrivate->SinglePathCount--; 636 637 if (mPrivate->ValidSinglePathCount > 0) { 638 mPrivate->ValidSinglePathCount--; 639 } 640 } 641 642 FreePool (AttemptConfigData); 643 } 644 } 645 646 // 647 // Free attempt is created but not saved to system. 648 // 649 if (mPrivate->NewAttempt != NULL) { 650 FreePool (mPrivate->NewAttempt); 651 mPrivate->NewAttempt = NULL; 652 } 653 654 return EFI_SUCCESS; 655 } 656 657 658 /** 659 Get the recorded NIC info from global structure by the Index. 660 661 @param[in] NicIndex The index indicates the position of NIC info. 662 663 @return Pointer to the NIC info, or NULL if not found. 664 665 **/ 666 ISCSI_NIC_INFO * 667 IScsiGetNicInfoByIndex ( 668 IN UINT8 NicIndex 669 ) 670 { 671 LIST_ENTRY *Entry; 672 ISCSI_NIC_INFO *NicInfo; 673 674 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) { 675 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link); 676 if (NicInfo->NicIndex == NicIndex) { 677 return NicInfo; 678 } 679 } 680 681 return NULL; 682 } 683 684 685 /** 686 Get the NIC's PCI location and return it according to the composited 687 format defined in iSCSI Boot Firmware Table. 688 689 @param[in] Controller The handle of the controller. 690 @param[out] Bus The bus number. 691 @param[out] Device The device number. 692 @param[out] Function The function number. 693 694 @return The composited representation of the NIC PCI location. 695 696 **/ 697 UINT16 698 IScsiGetNICPciLocation ( 699 IN EFI_HANDLE Controller, 700 OUT UINTN *Bus, 701 OUT UINTN *Device, 702 OUT UINTN *Function 703 ) 704 { 705 EFI_STATUS Status; 706 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 707 EFI_HANDLE PciIoHandle; 708 EFI_PCI_IO_PROTOCOL *PciIo; 709 UINTN Segment; 710 711 Status = gBS->HandleProtocol ( 712 Controller, 713 &gEfiDevicePathProtocolGuid, 714 (VOID **) &DevicePath 715 ); 716 if (EFI_ERROR (Status)) { 717 return 0; 718 } 719 720 Status = gBS->LocateDevicePath ( 721 &gEfiPciIoProtocolGuid, 722 &DevicePath, 723 &PciIoHandle 724 ); 725 if (EFI_ERROR (Status)) { 726 return 0; 727 } 728 729 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo); 730 if (EFI_ERROR (Status)) { 731 return 0; 732 } 733 734 Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function); 735 if (EFI_ERROR (Status)) { 736 return 0; 737 } 738 739 return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function); 740 } 741 742 743 /** 744 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated 745 buffer, and the size of the buffer. If failure, return NULL. 746 747 @param[in] Name String part of EFI variable name. 748 @param[in] VendorGuid GUID part of EFI variable name. 749 @param[out] VariableSize Returns the size of the EFI variable that was read. 750 751 @return Dynamically allocated memory that contains a copy of the EFI variable. 752 @return Caller is responsible freeing the buffer. 753 @retval NULL Variable was not read. 754 755 **/ 756 VOID * 757 IScsiGetVariableAndSize ( 758 IN CHAR16 *Name, 759 IN EFI_GUID *VendorGuid, 760 OUT UINTN *VariableSize 761 ) 762 { 763 EFI_STATUS Status; 764 UINTN BufferSize; 765 VOID *Buffer; 766 767 Buffer = NULL; 768 769 // 770 // Pass in a zero size buffer to find the required buffer size. 771 // 772 BufferSize = 0; 773 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); 774 if (Status == EFI_BUFFER_TOO_SMALL) { 775 // 776 // Allocate the buffer to return 777 // 778 Buffer = AllocateZeroPool (BufferSize); 779 if (Buffer == NULL) { 780 return NULL; 781 } 782 // 783 // Read variable into the allocated buffer. 784 // 785 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); 786 if (EFI_ERROR (Status)) { 787 BufferSize = 0; 788 } 789 } 790 791 *VariableSize = BufferSize; 792 return Buffer; 793 } 794 795 796 /** 797 Create the iSCSI driver data. 798 799 @param[in] Image The handle of the driver image. 800 @param[in] Controller The handle of the controller. 801 802 @return The iSCSI driver data created. 803 @retval NULL Other errors as indicated. 804 805 **/ 806 ISCSI_DRIVER_DATA * 807 IScsiCreateDriverData ( 808 IN EFI_HANDLE Image, 809 IN EFI_HANDLE Controller 810 ) 811 { 812 ISCSI_DRIVER_DATA *Private; 813 EFI_STATUS Status; 814 815 Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA)); 816 if (Private == NULL) { 817 return NULL; 818 } 819 820 Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE; 821 Private->Image = Image; 822 Private->Controller = Controller; 823 Private->Session = NULL; 824 825 // 826 // Create an event to be signaled when the BS to RT transition is triggerd so 827 // as to abort the iSCSI session. 828 // 829 Status = gBS->CreateEventEx ( 830 EVT_NOTIFY_SIGNAL, 831 TPL_CALLBACK, 832 IScsiOnExitBootService, 833 Private, 834 &gEfiEventExitBootServicesGuid, 835 &Private->ExitBootServiceEvent 836 ); 837 if (EFI_ERROR (Status)) { 838 FreePool (Private); 839 return NULL; 840 } 841 842 Private->ExtScsiPassThruHandle = NULL; 843 CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL)); 844 845 // 846 // 0 is designated to the TargetId, so use another value for the AdapterId. 847 // 848 Private->ExtScsiPassThruMode.AdapterId = 2; 849 Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL; 850 Private->ExtScsiPassThruMode.IoAlign = 4; 851 Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode; 852 853 return Private; 854 } 855 856 857 /** 858 Clean the iSCSI driver data. 859 860 @param[in] Private The iSCSI driver data. 861 862 @retval EFI_SUCCESS The clean operation is successful. 863 @retval Others Other errors as indicated. 864 865 **/ 866 EFI_STATUS 867 IScsiCleanDriverData ( 868 IN ISCSI_DRIVER_DATA *Private 869 ) 870 { 871 EFI_STATUS Status; 872 873 Status = EFI_SUCCESS; 874 875 if (Private->DevicePath != NULL) { 876 Status = gBS->UninstallProtocolInterface ( 877 Private->ExtScsiPassThruHandle, 878 &gEfiDevicePathProtocolGuid, 879 Private->DevicePath 880 ); 881 if (EFI_ERROR (Status)) { 882 goto EXIT; 883 } 884 885 FreePool (Private->DevicePath); 886 } 887 888 if (Private->ExtScsiPassThruHandle != NULL) { 889 Status = gBS->UninstallProtocolInterface ( 890 Private->ExtScsiPassThruHandle, 891 &gEfiExtScsiPassThruProtocolGuid, 892 &Private->IScsiExtScsiPassThru 893 ); 894 if (!EFI_ERROR (Status)) { 895 mPrivate->OneSessionEstablished = FALSE; 896 } 897 } 898 899 EXIT: 900 901 gBS->CloseEvent (Private->ExitBootServiceEvent); 902 903 mCallbackInfo->Current = NULL; 904 905 FreePool (Private); 906 return Status; 907 } 908 909 /** 910 Check wheather the Controller handle is configured to use DHCP protocol. 911 912 @param[in] Controller The handle of the controller. 913 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. 914 915 @retval TRUE The handle of the controller need the Dhcp protocol. 916 @retval FALSE The handle of the controller does not need the Dhcp protocol. 917 918 **/ 919 BOOLEAN 920 IScsiDhcpIsConfigured ( 921 IN EFI_HANDLE Controller, 922 IN UINT8 IpVersion 923 ) 924 { 925 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp; 926 UINT8 *AttemptConfigOrder; 927 UINTN AttemptConfigOrderSize; 928 UINTN Index; 929 EFI_STATUS Status; 930 EFI_MAC_ADDRESS MacAddr; 931 UINTN HwAddressSize; 932 UINT16 VlanId; 933 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; 934 CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE]; 935 936 AttemptConfigOrder = IScsiGetVariableAndSize ( 937 L"AttemptOrder", 938 &gIScsiConfigGuid, 939 &AttemptConfigOrderSize 940 ); 941 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) { 942 return FALSE; 943 } 944 945 // 946 // Get MAC address of this network device. 947 // 948 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize); 949 if(EFI_ERROR (Status)) { 950 return FALSE; 951 } 952 // 953 // Get VLAN ID of this network device. 954 // 955 VlanId = NetLibGetVlanId (Controller); 956 IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString); 957 958 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { 959 UnicodeSPrint ( 960 AttemptName, 961 (UINTN) 128, 962 L"%s%d", 963 MacString, 964 (UINTN) AttemptConfigOrder[Index] 965 ); 966 Status = GetVariable2 ( 967 AttemptName, 968 &gEfiIScsiInitiatorNameProtocolGuid, 969 (VOID**)&AttemptTmp, 970 NULL 971 ); 972 if(AttemptTmp == NULL || EFI_ERROR (Status)) { 973 continue; 974 } 975 976 ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex); 977 978 if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) { 979 FreePool (AttemptTmp); 980 continue; 981 } 982 983 if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG && 984 AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) { 985 FreePool (AttemptTmp); 986 continue; 987 } 988 989 if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG || 990 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE || 991 AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) { 992 FreePool (AttemptTmp); 993 FreePool (AttemptConfigOrder); 994 return TRUE; 995 } 996 997 FreePool (AttemptTmp); 998 } 999 1000 FreePool (AttemptConfigOrder); 1001 return FALSE; 1002 } 1003 1004 /** 1005 Get the various configuration data. 1006 1007 @param[in] Private The iSCSI driver data. 1008 1009 @retval EFI_SUCCESS The configuration data is retrieved. 1010 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet. 1011 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. 1012 1013 **/ 1014 EFI_STATUS 1015 IScsiGetConfigData ( 1016 IN ISCSI_DRIVER_DATA *Private 1017 ) 1018 { 1019 EFI_STATUS Status; 1020 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; 1021 UINTN Index; 1022 ISCSI_NIC_INFO *NicInfo; 1023 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; 1024 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp; 1025 UINT8 *AttemptConfigOrder; 1026 UINTN AttemptConfigOrderSize; 1027 CHAR16 IScsiMode[64]; 1028 CHAR16 IpMode[64]; 1029 1030 // 1031 // There should be at least one attempt configured. 1032 // 1033 AttemptConfigOrder = IScsiGetVariableAndSize ( 1034 L"AttemptOrder", 1035 &gIScsiConfigGuid, 1036 &AttemptConfigOrderSize 1037 ); 1038 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) { 1039 return EFI_NOT_FOUND; 1040 } 1041 1042 // 1043 // Get the iSCSI Initiator Name. 1044 // 1045 mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE; 1046 Status = gIScsiInitiatorName.Get ( 1047 &gIScsiInitiatorName, 1048 &mPrivate->InitiatorNameLength, 1049 mPrivate->InitiatorName 1050 ); 1051 if (EFI_ERROR (Status)) { 1052 return Status; 1053 } 1054 1055 // 1056 // Get the normal configuration. 1057 // 1058 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { 1059 1060 // 1061 // Check whether the attempt exists in AttemptConfig. 1062 // 1063 AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]); 1064 if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) { 1065 continue; 1066 } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) { 1067 // 1068 // Check the autoconfig path to see whether it should be retried. 1069 // 1070 if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && 1071 !AttemptTmp->AutoConfigureSuccess) { 1072 if (mPrivate->Ipv6Flag && 1073 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) { 1074 // 1075 // Autoconfigure for IP6 already attempted but failed. Do not try again. 1076 // 1077 continue; 1078 } else if (!mPrivate->Ipv6Flag && 1079 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) { 1080 // 1081 // Autoconfigure for IP4 already attempted but failed. Do not try again. 1082 // 1083 continue; 1084 } else { 1085 // 1086 // Try another approach for this autoconfigure path. 1087 // 1088 AttemptTmp->AutoConfigureMode = 1089 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4); 1090 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE; 1091 AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE; 1092 AttemptTmp->DhcpSuccess = FALSE; 1093 1094 // 1095 // Get some information from the dhcp server. 1096 // 1097 if (!mPrivate->Ipv6Flag) { 1098 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp); 1099 if (!EFI_ERROR (Status)) { 1100 AttemptTmp->DhcpSuccess = TRUE; 1101 } 1102 } else { 1103 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp); 1104 if (!EFI_ERROR (Status)) { 1105 AttemptTmp->DhcpSuccess = TRUE; 1106 } 1107 } 1108 1109 // 1110 // Refresh the state of this attempt to NVR. 1111 // 1112 AsciiStrToUnicodeStrS (AttemptTmp->MacString, MacString, ARRAY_SIZE (MacString)); 1113 UnicodeSPrint ( 1114 mPrivate->PortString, 1115 (UINTN) ISCSI_NAME_IFR_MAX_SIZE, 1116 L"%s%d", 1117 MacString, 1118 (UINTN) AttemptTmp->AttemptConfigIndex 1119 ); 1120 1121 gRT->SetVariable ( 1122 mPrivate->PortString, 1123 &gEfiIScsiInitiatorNameProtocolGuid, 1124 ISCSI_CONFIG_VAR_ATTR, 1125 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), 1126 AttemptTmp 1127 ); 1128 1129 continue; 1130 } 1131 } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) { 1132 // 1133 // Get DHCP information for already added, but failed, attempt. 1134 // 1135 AttemptTmp->DhcpSuccess = FALSE; 1136 if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) { 1137 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp); 1138 if (!EFI_ERROR (Status)) { 1139 AttemptTmp->DhcpSuccess = TRUE; 1140 } 1141 } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) { 1142 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp); 1143 if (!EFI_ERROR (Status)) { 1144 AttemptTmp->DhcpSuccess = TRUE; 1145 } 1146 } 1147 1148 // 1149 // Refresh the state of this attempt to NVR. 1150 // 1151 AsciiStrToUnicodeStrS (AttemptTmp->MacString, MacString, ARRAY_SIZE (MacString)); 1152 UnicodeSPrint ( 1153 mPrivate->PortString, 1154 (UINTN) ISCSI_NAME_IFR_MAX_SIZE, 1155 L"%s%d", 1156 MacString, 1157 (UINTN) AttemptTmp->AttemptConfigIndex 1158 ); 1159 1160 gRT->SetVariable ( 1161 mPrivate->PortString, 1162 &gEfiIScsiInitiatorNameProtocolGuid, 1163 ISCSI_CONFIG_VAR_ATTR, 1164 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), 1165 AttemptTmp 1166 ); 1167 1168 continue; 1169 1170 } else { 1171 continue; 1172 } 1173 } 1174 1175 // 1176 // This attempt does not exist in AttemptConfig. Try to add a new one. 1177 // 1178 1179 NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic); 1180 ASSERT (NicInfo != NULL); 1181 IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString); 1182 UnicodeSPrint ( 1183 mPrivate->PortString, 1184 (UINTN) 128, 1185 L"%s%d", 1186 MacString, 1187 (UINTN) AttemptConfigOrder[Index] 1188 ); 1189 1190 GetVariable2 ( 1191 mPrivate->PortString, 1192 &gEfiIScsiInitiatorNameProtocolGuid, 1193 (VOID**)&AttemptConfigData, 1194 NULL 1195 ); 1196 1197 if (AttemptConfigData == NULL) { 1198 continue; 1199 } 1200 1201 ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex); 1202 1203 AttemptConfigData->NicIndex = NicInfo->NicIndex; 1204 AttemptConfigData->DhcpSuccess = FALSE; 1205 AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE); 1206 AttemptConfigData->ValidPath = FALSE; 1207 1208 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) { 1209 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE; 1210 AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE; 1211 1212 AttemptConfigData->AutoConfigureMode = 1213 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4); 1214 AttemptConfigData->AutoConfigureSuccess = FALSE; 1215 } 1216 1217 // 1218 // Get some information from dhcp server. 1219 // 1220 if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED && 1221 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) { 1222 1223 if (!mPrivate->Ipv6Flag && 1224 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 || 1225 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) { 1226 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData); 1227 if (!EFI_ERROR (Status)) { 1228 AttemptConfigData->DhcpSuccess = TRUE; 1229 } 1230 } else if (mPrivate->Ipv6Flag && 1231 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 || 1232 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) { 1233 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData); 1234 if (!EFI_ERROR (Status)) { 1235 AttemptConfigData->DhcpSuccess = TRUE; 1236 } 1237 } 1238 1239 // 1240 // Refresh the state of this attempt to NVR. 1241 // 1242 AsciiStrToUnicodeStrS (AttemptConfigData->MacString, MacString, ARRAY_SIZE (MacString)); 1243 UnicodeSPrint ( 1244 mPrivate->PortString, 1245 (UINTN) ISCSI_NAME_IFR_MAX_SIZE, 1246 L"%s%d", 1247 MacString, 1248 (UINTN) AttemptConfigData->AttemptConfigIndex 1249 ); 1250 1251 gRT->SetVariable ( 1252 mPrivate->PortString, 1253 &gEfiIScsiInitiatorNameProtocolGuid, 1254 ISCSI_CONFIG_VAR_ATTR, 1255 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), 1256 AttemptConfigData 1257 ); 1258 } 1259 1260 // 1261 // Update Attempt Help Info. 1262 // 1263 1264 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) { 1265 UnicodeSPrint (IScsiMode, 64, L"Disabled"); 1266 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) { 1267 UnicodeSPrint (IScsiMode, 64, L"Enabled"); 1268 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { 1269 UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO"); 1270 } 1271 1272 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) { 1273 UnicodeSPrint (IpMode, 64, L"IP4"); 1274 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) { 1275 UnicodeSPrint (IpMode, 64, L"IP6"); 1276 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) { 1277 UnicodeSPrint (IpMode, 64, L"Autoconfigure"); 1278 } 1279 1280 UnicodeSPrint ( 1281 mPrivate->PortString, 1282 (UINTN) ISCSI_NAME_IFR_MAX_SIZE, 1283 L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s", 1284 MacString, 1285 NicInfo->BusNumber, 1286 NicInfo->DeviceNumber, 1287 NicInfo->FunctionNumber, 1288 IScsiMode, 1289 IpMode 1290 ); 1291 1292 AttemptConfigData->AttemptTitleHelpToken = HiiSetString ( 1293 mCallbackInfo->RegisteredHandle, 1294 0, 1295 mPrivate->PortString, 1296 NULL 1297 ); 1298 if (AttemptConfigData->AttemptTitleHelpToken == 0) { 1299 return EFI_OUT_OF_RESOURCES; 1300 } 1301 1302 // 1303 // Record the attempt in global link list. 1304 // 1305 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link); 1306 mPrivate->AttemptCount++; 1307 1308 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { 1309 mPrivate->MpioCount++; 1310 mPrivate->EnableMpio = TRUE; 1311 1312 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) { 1313 mPrivate->Krb5MpioCount++; 1314 } 1315 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) { 1316 mPrivate->SinglePathCount++; 1317 } 1318 } 1319 1320 // 1321 // Reorder the AttemptConfig by the configured order. 1322 // 1323 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { 1324 AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]); 1325 if (AttemptConfigData == NULL) { 1326 continue; 1327 } 1328 1329 RemoveEntryList (&AttemptConfigData->Link); 1330 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link); 1331 } 1332 1333 // 1334 // Update the Main Form. 1335 // 1336 IScsiConfigUpdateAttempt (); 1337 1338 FreePool (AttemptConfigOrder); 1339 1340 // 1341 // There should be at least one attempt configuration. 1342 // 1343 if (!mPrivate->EnableMpio) { 1344 if (mPrivate->SinglePathCount == 0) { 1345 return EFI_NOT_FOUND; 1346 } 1347 mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount; 1348 } 1349 1350 return EFI_SUCCESS; 1351 } 1352 1353 1354 /** 1355 Get the device path of the iSCSI tcp connection and update it. 1356 1357 @param Session The iSCSI session. 1358 1359 @return The updated device path. 1360 @retval NULL Other errors as indicated. 1361 1362 **/ 1363 EFI_DEVICE_PATH_PROTOCOL * 1364 IScsiGetTcpConnDevicePath ( 1365 IN ISCSI_SESSION *Session 1366 ) 1367 { 1368 ISCSI_CONNECTION *Conn; 1369 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 1370 EFI_STATUS Status; 1371 EFI_DEV_PATH *DPathNode; 1372 UINTN PathLen; 1373 1374 if (Session->State != SESSION_STATE_LOGGED_IN) { 1375 return NULL; 1376 } 1377 1378 Conn = NET_LIST_USER_STRUCT_S ( 1379 Session->Conns.ForwardLink, 1380 ISCSI_CONNECTION, 1381 Link, 1382 ISCSI_CONNECTION_SIGNATURE 1383 ); 1384 1385 Status = gBS->HandleProtocol ( 1386 Conn->TcpIo.Handle, 1387 &gEfiDevicePathProtocolGuid, 1388 (VOID **) &DevicePath 1389 ); 1390 if (EFI_ERROR (Status)) { 1391 return NULL; 1392 } 1393 // 1394 // Duplicate it. 1395 // 1396 DevicePath = DuplicateDevicePath (DevicePath); 1397 if (DevicePath == NULL) { 1398 return NULL; 1399 } 1400 1401 DPathNode = (EFI_DEV_PATH *) DevicePath; 1402 1403 while (!IsDevicePathEnd (&DPathNode->DevPath)) { 1404 if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) { 1405 if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) { 1406 DPathNode->Ipv4.LocalPort = 0; 1407 1408 DPathNode->Ipv4.StaticIpAddress = 1409 (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp); 1410 1411 // 1412 // Add a judgement here to support previous versions of IPv4_DEVICE_PATH. 1413 // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask 1414 // do not exist. 1415 // In new version of IPv4_DEVICE_PATH, structcure length is 27. 1416 // 1417 1418 PathLen = DevicePathNodeLength (&DPathNode->Ipv4); 1419 1420 if (PathLen == IP4_NODE_LEN_NEW_VERSIONS) { 1421 1422 IP4_COPY_ADDRESS ( 1423 &DPathNode->Ipv4.GatewayIpAddress, 1424 &Session->ConfigData->SessionConfigData.Gateway 1425 ); 1426 1427 IP4_COPY_ADDRESS ( 1428 &DPathNode->Ipv4.SubnetMask, 1429 &Session->ConfigData->SessionConfigData.SubnetMask 1430 ); 1431 } 1432 1433 break; 1434 } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) { 1435 DPathNode->Ipv6.LocalPort = 0; 1436 1437 // 1438 // Add a judgement here to support previous versions of IPv6_DEVICE_PATH. 1439 // In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength 1440 // and GatewayIpAddress do not exist. 1441 // In new version of IPv6_DEVICE_PATH, structure length is 60, while in 1442 // old versions, the length is 43. 1443 // 1444 1445 PathLen = DevicePathNodeLength (&DPathNode->Ipv6); 1446 1447 if (PathLen == IP6_NODE_LEN_NEW_VERSIONS ) { 1448 1449 DPathNode->Ipv6.IpAddressOrigin = 0; 1450 DPathNode->Ipv6.PrefixLength = IP6_PREFIX_LENGTH; 1451 ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS)); 1452 } 1453 else if (PathLen == IP6_NODE_LEN_OLD_VERSIONS) { 1454 1455 // 1456 // StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new 1457 // version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH. 1458 // 1459 *((UINT8 *)(&DPathNode->Ipv6) + IP6_OLD_IPADDRESS_OFFSET) = 1460 (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp); 1461 } 1462 1463 break; 1464 } 1465 } 1466 1467 DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath); 1468 } 1469 1470 return DevicePath; 1471 } 1472 1473 1474 /** 1475 Abort the session when the transition from BS to RT is initiated. 1476 1477 @param[in] Event The event signaled. 1478 @param[in] Context The iSCSI driver data. 1479 1480 **/ 1481 VOID 1482 EFIAPI 1483 IScsiOnExitBootService ( 1484 IN EFI_EVENT Event, 1485 IN VOID *Context 1486 ) 1487 { 1488 ISCSI_DRIVER_DATA *Private; 1489 1490 Private = (ISCSI_DRIVER_DATA *) Context; 1491 gBS->CloseEvent (Private->ExitBootServiceEvent); 1492 1493 if (Private->Session != NULL) { 1494 IScsiSessionAbort (Private->Session); 1495 } 1496 } 1497 1498 /** 1499 Tests whether a controller handle is being managed by IScsi driver. 1500 1501 This function tests whether the driver specified by DriverBindingHandle is 1502 currently managing the controller specified by ControllerHandle. This test 1503 is performed by evaluating if the the protocol specified by ProtocolGuid is 1504 present on ControllerHandle and is was opened by DriverBindingHandle and Nic 1505 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER. 1506 If ProtocolGuid is NULL, then ASSERT(). 1507 1508 @param ControllerHandle A handle for a controller to test. 1509 @param DriverBindingHandle Specifies the driver binding handle for the 1510 driver. 1511 @param ProtocolGuid Specifies the protocol that the driver specified 1512 by DriverBindingHandle opens in its Start() 1513 function. 1514 1515 @retval EFI_SUCCESS ControllerHandle is managed by the driver 1516 specified by DriverBindingHandle. 1517 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver 1518 specified by DriverBindingHandle. 1519 1520 **/ 1521 EFI_STATUS 1522 EFIAPI 1523 IScsiTestManagedDevice ( 1524 IN EFI_HANDLE ControllerHandle, 1525 IN EFI_HANDLE DriverBindingHandle, 1526 IN EFI_GUID *ProtocolGuid 1527 ) 1528 { 1529 EFI_STATUS Status; 1530 VOID *ManagedInterface; 1531 EFI_HANDLE NicControllerHandle; 1532 1533 ASSERT (ProtocolGuid != NULL); 1534 1535 NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid); 1536 if (NicControllerHandle == NULL) { 1537 return EFI_UNSUPPORTED; 1538 } 1539 1540 Status = gBS->OpenProtocol ( 1541 ControllerHandle, 1542 (EFI_GUID *) ProtocolGuid, 1543 &ManagedInterface, 1544 DriverBindingHandle, 1545 NicControllerHandle, 1546 EFI_OPEN_PROTOCOL_BY_DRIVER 1547 ); 1548 if (!EFI_ERROR (Status)) { 1549 gBS->CloseProtocol ( 1550 ControllerHandle, 1551 (EFI_GUID *) ProtocolGuid, 1552 DriverBindingHandle, 1553 NicControllerHandle 1554 ); 1555 return EFI_UNSUPPORTED; 1556 } 1557 1558 if (Status != EFI_ALREADY_STARTED) { 1559 return EFI_UNSUPPORTED; 1560 } 1561 1562 return EFI_SUCCESS; 1563 } 1564