2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2018, 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
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.
15 #include "IScsiImpl.h"
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
20 Removes (trims) specified leading and trailing characters from a string.
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed. On return,
23 Str will hold the trimmed string.
25 @param[in] CharC Character will be trimmed from str.
41 // Trim off the leading and trailing characters c
43 for (Pointer1
= Str
; (*Pointer1
!= 0) && (*Pointer1
== CharC
); Pointer1
++) {
48 if (Pointer2
== Pointer1
) {
49 while (*Pointer1
!= 0) {
54 while (*Pointer1
!= 0) {
55 *Pointer2
= *Pointer1
;
63 for (Pointer1
= Str
+ StrLen(Str
) - 1; Pointer1
>= Str
&& *Pointer1
== CharC
; Pointer1
--) {
66 if (Pointer1
!= Str
+ StrLen(Str
) - 1) {
72 Calculate the prefix length of the IPv4 subnet mask.
74 @param[in] SubnetMask The IPv4 subnet mask.
76 @return The prefix length of the subnet mask.
77 @retval 0 Other errors as indicated.
80 IScsiGetSubnetMaskPrefixLength (
81 IN EFI_IPv4_ADDRESS
*SubnetMask
88 // The SubnetMask is in network byte order.
90 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
95 ReverseMask
= ~ReverseMask
;
97 if ((ReverseMask
& (ReverseMask
+ 1)) != 0) {
103 while (ReverseMask
!= 0) {
104 ReverseMask
= ReverseMask
>> 1;
108 return (UINT8
) (32 - Len
);
112 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
114 @param[in] Str The hexadecimal encoded LUN string.
115 @param[out] Lun Storage to return the 64-bit LUN.
117 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
118 @retval EFI_INVALID_PARAMETER The string is malformatted.
126 UINTN Index
, IndexValue
, IndexNum
, SizeStr
;
133 ZeroMem ((UINT8
*) Value
, sizeof (Value
));
134 SizeStr
= AsciiStrLen (Str
);
138 for (Index
= 0; Index
< SizeStr
; Index
++) {
139 TemStr
[0] = Str
[Index
];
140 TemValue
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
141 if (TemValue
== 0 && TemStr
[0] != '0') {
142 if ((TemStr
[0] != '-') || (IndexNum
== 0)) {
146 return EFI_INVALID_PARAMETER
;
150 if ((TemValue
== 0) && (TemStr
[0] == '-')) {
154 if (++IndexValue
>= 4) {
158 return EFI_INVALID_PARAMETER
;
161 // Restart str index for the next lun value
167 if (++IndexNum
> 4) {
169 // Each Lun Str can't exceed size 4, because it will be as UINT16 value
171 return EFI_INVALID_PARAMETER
;
175 // Combine UINT16 value
177 Value
[IndexValue
] = (UINT16
) ((Value
[IndexValue
] << 4) + TemValue
);
180 for (Index
= 0; Index
<= IndexValue
; Index
++) {
181 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Value
[Index
]);
188 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
190 @param[in] Lun The 64-bit LUN.
191 @param[out] Str The storage to return the hexadecimal encoded LUN string.
194 IScsiLunToUnicodeStr (
204 for (Index
= 0; Index
< 4; Index
++) {
206 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
207 CopyMem(TempStr
, L
"0-", sizeof (L
"0-"));
209 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
210 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0x0F];
211 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
212 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0x0F];
216 StrTrim (TempStr
, L
'0');
219 TempStr
+= StrLen (TempStr
);
222 ASSERT (StrLen(Str
) >= 1);
223 Str
[StrLen (Str
) - 1] = 0;
225 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
226 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
235 Convert the ASCII string into a UNICODE string.
237 @param[in] Source The ASCII string.
238 @param[out] Destination The storage to return the UNICODE string.
240 @return CHAR16 * Pointer to the UNICODE string.
243 IScsiAsciiStrToUnicodeStr (
245 OUT CHAR16
*Destination
248 ASSERT (Destination
!= NULL
);
249 ASSERT (Source
!= NULL
);
251 while (*Source
!= '\0') {
252 *(Destination
++) = (CHAR16
) *(Source
++);
261 Convert the UNICODE string into an ASCII string.
263 @param[in] Source The UNICODE string.
264 @param[out] Destination The storage to return the ASCII string.
266 @return CHAR8 * Pointer to the ASCII string.
269 IScsiUnicodeStrToAsciiStr (
271 OUT CHAR8
*Destination
274 ASSERT (Destination
!= NULL
);
275 ASSERT (Source
!= NULL
);
277 while (*Source
!= '\0') {
279 // If any Unicode characters in Source contain
280 // non-zero value in the upper 8 bits, then ASSERT().
282 ASSERT (*Source
< 0x100);
283 *(Destination
++) = (CHAR8
) *(Source
++);
292 Convert the decimal dotted IPv4 address into the binary IPv4 address.
294 @param[in] Str The UNICODE string.
295 @param[out] Ip The storage to return the ASCII string.
297 @retval EFI_SUCCESS The binary IP address is returned in Ip.
298 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
303 OUT EFI_IPv4_ADDRESS
*Ip
314 return EFI_INVALID_PARAMETER
;
318 while (NET_IS_DIGIT (*Str
)) {
319 Number
= Number
* 10 + (*Str
- '0');
324 return EFI_INVALID_PARAMETER
;
327 Ip
->Addr
[Index
] = (UINT8
) Number
;
329 if ((*Str
!= '\0') && (*Str
!= '.')) {
331 // The current character should be either the NULL terminator or
332 // the dot delimiter.
334 return EFI_INVALID_PARAMETER
;
339 // Skip the delimiter.
348 return EFI_INVALID_PARAMETER
;
355 Convert the mac address into a hexadecimal encoded "-" seperated string.
357 @param[in] Mac The mac address.
358 @param[in] Len Length in bytes of the mac address.
359 @param[in] VlanId VLAN ID of the network device.
360 @param[out] Str The storage to return the mac string.
364 IN EFI_MAC_ADDRESS
*Mac
,
373 for (Index
= 0; Index
< Len
; Index
++) {
374 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
375 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
376 Str
[3 * Index
+ 2] = L
'-';
379 String
= &Str
[3 * Index
- 1] ;
381 String
+= UnicodeSPrint (String
, 6 * sizeof (CHAR16
), L
"\\%04x", (UINTN
) VlanId
);
388 Convert the binary encoded buffer into a hexadecimal encoded string.
390 @param[in] BinBuffer The buffer containing the binary data.
391 @param[in] BinLength Length of the binary buffer.
392 @param[in, out] HexStr Pointer to the string.
393 @param[in, out] HexLength The length of the string.
395 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
396 and the length of the string is updated.
397 @retval EFI_BUFFER_TOO_SMALL The string is too small.
398 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
404 IN OUT CHAR8
*HexStr
,
405 IN OUT UINT32
*HexLength
410 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
411 return EFI_INVALID_PARAMETER
;
414 if (((*HexLength
) - 3) < BinLength
* 2) {
415 *HexLength
= BinLength
* 2 + 3;
416 return EFI_BUFFER_TOO_SMALL
;
419 *HexLength
= BinLength
* 2 + 3;
421 // Prefix for Hex String
426 for (Index
= 0; Index
< BinLength
; Index
++) {
427 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
428 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0x0F];
431 HexStr
[Index
* 2 + 2] = '\0';
437 Convert the hexadecimal string into a binary encoded buffer.
439 @param[in, out] BinBuffer The binary buffer.
440 @param[in, out] BinLength Length of the binary buffer.
441 @param[in] HexStr The hexadecimal string.
443 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
445 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
449 IN OUT UINT8
*BinBuffer
,
450 IN OUT UINT32
*BinLength
,
459 ZeroMem (TemStr
, sizeof (TemStr
));
462 // Find out how many hex characters the string has.
464 if ((HexStr
[0] == '0') && ((HexStr
[1] == 'x') || (HexStr
[1] == 'X'))) {
468 Length
= AsciiStrLen (HexStr
);
470 for (Index
= 0; Index
< Length
; Index
++) {
471 TemStr
[0] = HexStr
[Index
];
472 Digit
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
473 if (Digit
== 0 && TemStr
[0] != '0') {
479 if ((Index
& 1) == 0) {
480 BinBuffer
[Index
/2] = Digit
;
482 BinBuffer
[Index
/2] = (UINT8
) ((BinBuffer
[Index
/2] << 4) + Digit
);
486 *BinLength
= (UINT32
) ((Index
+ 1)/2);
492 Generate random numbers.
494 @param[in, out] Rand The buffer to contain random numbers.
495 @param[in] RandLength The length of the Rand buffer.
505 while (RandLength
> 0) {
506 Random
= NET_RANDOM (NetRandomInitSeed ());
507 *Rand
++ = (UINT8
) (Random
);
513 Create the iSCSI driver data..
515 @param[in] Image The handle of the driver image.
516 @param[in] Controller The handle of the controller.
518 @return The iSCSI driver data created.
519 @retval NULL Other errors as indicated.
522 IScsiCreateDriverData (
524 IN EFI_HANDLE Controller
527 ISCSI_DRIVER_DATA
*Private
;
530 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
531 if (Private
== NULL
) {
535 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
536 Private
->Image
= Image
;
537 Private
->Controller
= Controller
;
540 // Create an event to be signal when the BS to RT transition is triggerd so
541 // as to abort the iSCSI session.
543 Status
= gBS
->CreateEventEx (
546 IScsiOnExitBootService
,
548 &gEfiEventExitBootServicesGuid
,
549 &Private
->ExitBootServiceEvent
551 if (EFI_ERROR (Status
)) {
556 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
559 // 0 is designated to the TargetId, so use another value for the AdapterId.
561 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
562 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
563 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
564 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
567 // Install the Ext SCSI PASS THRU protocol.
569 Status
= gBS
->InstallProtocolInterface (
570 &Private
->ExtScsiPassThruHandle
,
571 &gEfiExtScsiPassThruProtocolGuid
,
572 EFI_NATIVE_INTERFACE
,
573 &Private
->IScsiExtScsiPassThru
575 if (EFI_ERROR (Status
)) {
576 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
582 IScsiSessionInit (&Private
->Session
, FALSE
);
588 Clean the iSCSI driver data.
590 @param[in] Private The iSCSI driver data.
592 @retval EFI_SUCCESS The clean operation is successful.
593 @retval Others Other errors as indicated.
597 IScsiCleanDriverData (
598 IN ISCSI_DRIVER_DATA
*Private
603 Status
= EFI_SUCCESS
;
605 if (Private
->DevicePath
!= NULL
) {
606 Status
= gBS
->UninstallProtocolInterface (
607 Private
->ExtScsiPassThruHandle
,
608 &gEfiDevicePathProtocolGuid
,
611 if (EFI_ERROR (Status
)) {
615 FreePool (Private
->DevicePath
);
618 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
619 Status
= gBS
->UninstallProtocolInterface (
620 Private
->ExtScsiPassThruHandle
,
621 &gEfiExtScsiPassThruProtocolGuid
,
622 &Private
->IScsiExtScsiPassThru
627 if (Private
->ExitBootServiceEvent
!= NULL
) {
628 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
636 Check wheather the Controller is configured to use DHCP protocol.
638 @param[in] Controller The handle of the controller.
640 @retval TRUE The handle of the controller need the Dhcp protocol.
641 @retval FALSE The handle of the controller does not need the Dhcp protocol.
645 IScsiDhcpIsConfigured (
646 IN EFI_HANDLE Controller
650 EFI_MAC_ADDRESS MacAddress
;
653 CHAR16 MacString
[70];
654 ISCSI_SESSION_CONFIG_NVDATA
*ConfigDataTmp
;
657 // Get the mac string, it's the name of various variable
659 Status
= NetLibGetMacAddress (Controller
, &MacAddress
, &HwAddressSize
);
660 if (EFI_ERROR (Status
)) {
663 VlanId
= NetLibGetVlanId (Controller
);
664 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
667 // Get the normal configuration.
669 Status
= GetVariable2 (
671 &gEfiIScsiInitiatorNameProtocolGuid
,
672 (VOID
**)&ConfigDataTmp
,
675 if (ConfigDataTmp
== NULL
|| EFI_ERROR (Status
)) {
679 if (ConfigDataTmp
->Enabled
&& ConfigDataTmp
->InitiatorInfoFromDhcp
) {
680 FreePool (ConfigDataTmp
);
684 FreePool (ConfigDataTmp
);
689 Get the various configuration data of this iSCSI instance.
691 @param[in] Private The iSCSI driver data.
693 @retval EFI_SUCCESS The configuration of this instance is got.
694 @retval EFI_ABORTED The operation was aborted.
695 @retval Others Other errors as indicated.
699 IN ISCSI_DRIVER_DATA
*Private
703 ISCSI_SESSION
*Session
;
705 EFI_MAC_ADDRESS MacAddress
;
708 CHAR16 MacString
[70];
711 // get the iSCSI Initiator Name
713 Session
= &Private
->Session
;
714 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
715 Status
= gIScsiInitiatorName
.Get (
716 &gIScsiInitiatorName
,
717 &Session
->InitiatorNameLength
,
718 Session
->InitiatorName
720 if (EFI_ERROR (Status
)) {
725 // Get the mac string, it's the name of various variable
727 Status
= NetLibGetMacAddress (Private
->Controller
, &MacAddress
, &HwAddressSize
);
728 ASSERT (Status
== EFI_SUCCESS
);
729 VlanId
= NetLibGetVlanId (Private
->Controller
);
730 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
733 // Get the normal configuration.
735 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
736 Status
= gRT
->GetVariable (
738 &gEfiIScsiInitiatorNameProtocolGuid
,
741 &Session
->ConfigData
.NvData
743 if (EFI_ERROR (Status
)) {
747 if (!Session
->ConfigData
.NvData
.Enabled
) {
751 // Get the CHAP Auth information.
753 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
754 Status
= gRT
->GetVariable (
756 &gIScsiCHAPAuthInfoGuid
,
759 &Session
->AuthData
.AuthConfig
762 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
766 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
773 Get the device path of the iSCSI tcp connection and update it.
775 @param[in] Private The iSCSI driver data.
777 @return The updated device path.
778 @retval NULL Other errors as indicated.
780 EFI_DEVICE_PATH_PROTOCOL
*
781 IScsiGetTcpConnDevicePath (
782 IN ISCSI_DRIVER_DATA
*Private
785 ISCSI_SESSION
*Session
;
786 ISCSI_CONNECTION
*Conn
;
788 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
790 EFI_DEV_PATH
*DPathNode
;
792 Session
= &Private
->Session
;
793 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
797 Conn
= NET_LIST_USER_STRUCT_S (
798 Session
->Conns
.ForwardLink
,
801 ISCSI_CONNECTION_SIGNATURE
803 Tcp4Io
= &Conn
->Tcp4Io
;
805 Status
= gBS
->HandleProtocol (
807 &gEfiDevicePathProtocolGuid
,
810 if (EFI_ERROR (Status
)) {
816 DevicePath
= DuplicateDevicePath (DevicePath
);
817 if (DevicePath
== NULL
) {
821 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
823 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
824 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
825 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
828 DPathNode
->Ipv4
.LocalPort
= 0;
829 DPathNode
->Ipv4
.StaticIpAddress
=
830 (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
833 // Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
834 // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
836 // In new version of IPv4_DEVICE_PATH, structcure length is 27.
838 if (DevicePathNodeLength (&DPathNode
->Ipv4
) == IP4_NODE_LEN_NEW_VERSIONS
) {
841 &DPathNode
->Ipv4
.GatewayIpAddress
,
842 &Session
->ConfigData
.NvData
.Gateway
846 &DPathNode
->Ipv4
.SubnetMask
,
847 &Session
->ConfigData
.NvData
.SubnetMask
854 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
861 Abort the session when the transition from BS to RT is initiated.
863 @param[in] Event The event signaled.
864 @param[in] Context The iSCSI driver data.
868 IScsiOnExitBootService (
873 ISCSI_DRIVER_DATA
*Private
;
875 Private
= (ISCSI_DRIVER_DATA
*) Context
;
877 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
878 Private
->ExitBootServiceEvent
= NULL
;
880 IScsiSessionAbort (&Private
->Session
);
884 Tests whether a controller handle is being managed by IScsi driver.
886 This function tests whether the driver specified by DriverBindingHandle is
887 currently managing the controller specified by ControllerHandle. This test
888 is performed by evaluating if the the protocol specified by ProtocolGuid is
889 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
890 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
891 If ProtocolGuid is NULL, then ASSERT().
893 @param ControllerHandle A handle for a controller to test.
894 @param DriverBindingHandle Specifies the driver binding handle for the
896 @param ProtocolGuid Specifies the protocol that the driver specified
897 by DriverBindingHandle opens in its Start()
900 @retval EFI_SUCCESS ControllerHandle is managed by the driver
901 specified by DriverBindingHandle.
902 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
903 specified by DriverBindingHandle.
908 IScsiTestManagedDevice (
909 IN EFI_HANDLE ControllerHandle
,
910 IN EFI_HANDLE DriverBindingHandle
,
911 IN EFI_GUID
*ProtocolGuid
915 VOID
*ManagedInterface
;
916 EFI_HANDLE NicControllerHandle
;
918 ASSERT (ProtocolGuid
!= NULL
);
920 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
921 if (NicControllerHandle
== NULL
) {
922 return EFI_UNSUPPORTED
;
925 Status
= gBS
->OpenProtocol (
927 (EFI_GUID
*) ProtocolGuid
,
931 EFI_OPEN_PROTOCOL_BY_DRIVER
933 if (!EFI_ERROR (Status
)) {
936 (EFI_GUID
*) ProtocolGuid
,
940 return EFI_UNSUPPORTED
;
943 if (Status
!= EFI_ALREADY_STARTED
) {
944 return EFI_UNSUPPORTED
;