2 Miscellaneous routines for iSCSI driver.
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
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
628 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
635 Check wheather the Controller is configured to use DHCP protocol.
637 @param[in] Controller The handle of the controller.
639 @retval TRUE The handle of the controller need the Dhcp protocol.
640 @retval FALSE The handle of the controller does not need the Dhcp protocol.
644 IScsiDhcpIsConfigured (
645 IN EFI_HANDLE Controller
649 EFI_MAC_ADDRESS MacAddress
;
652 CHAR16 MacString
[70];
653 ISCSI_SESSION_CONFIG_NVDATA
*ConfigDataTmp
;
656 // Get the mac string, it's the name of various variable
658 Status
= NetLibGetMacAddress (Controller
, &MacAddress
, &HwAddressSize
);
659 if (EFI_ERROR (Status
)) {
662 VlanId
= NetLibGetVlanId (Controller
);
663 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
666 // Get the normal configuration.
668 Status
= GetVariable2 (
670 &gEfiIScsiInitiatorNameProtocolGuid
,
671 (VOID
**)&ConfigDataTmp
,
674 if (ConfigDataTmp
== NULL
|| EFI_ERROR (Status
)) {
678 if (ConfigDataTmp
->Enabled
&& ConfigDataTmp
->InitiatorInfoFromDhcp
) {
679 FreePool (ConfigDataTmp
);
683 FreePool (ConfigDataTmp
);
688 Get the various configuration data of this iSCSI instance.
690 @param[in] Private The iSCSI driver data.
692 @retval EFI_SUCCESS The configuration of this instance is got.
693 @retval EFI_ABORTED The operation was aborted.
694 @retval Others Other errors as indicated.
698 IN ISCSI_DRIVER_DATA
*Private
702 ISCSI_SESSION
*Session
;
704 EFI_MAC_ADDRESS MacAddress
;
707 CHAR16 MacString
[70];
710 // get the iSCSI Initiator Name
712 Session
= &Private
->Session
;
713 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
714 Status
= gIScsiInitiatorName
.Get (
715 &gIScsiInitiatorName
,
716 &Session
->InitiatorNameLength
,
717 Session
->InitiatorName
719 if (EFI_ERROR (Status
)) {
724 // Get the mac string, it's the name of various variable
726 Status
= NetLibGetMacAddress (Private
->Controller
, &MacAddress
, &HwAddressSize
);
727 ASSERT (Status
== EFI_SUCCESS
);
728 VlanId
= NetLibGetVlanId (Private
->Controller
);
729 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
732 // Get the normal configuration.
734 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
735 Status
= gRT
->GetVariable (
737 &gEfiIScsiInitiatorNameProtocolGuid
,
740 &Session
->ConfigData
.NvData
742 if (EFI_ERROR (Status
)) {
746 if (!Session
->ConfigData
.NvData
.Enabled
) {
750 // Get the CHAP Auth information.
752 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
753 Status
= gRT
->GetVariable (
755 &gIScsiCHAPAuthInfoGuid
,
758 &Session
->AuthData
.AuthConfig
761 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
765 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
772 Get the device path of the iSCSI tcp connection and update it.
774 @param[in] Private The iSCSI driver data.
776 @return The updated device path.
777 @retval NULL Other errors as indicated.
779 EFI_DEVICE_PATH_PROTOCOL
*
780 IScsiGetTcpConnDevicePath (
781 IN ISCSI_DRIVER_DATA
*Private
784 ISCSI_SESSION
*Session
;
785 ISCSI_CONNECTION
*Conn
;
787 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
789 EFI_DEV_PATH
*DPathNode
;
791 Session
= &Private
->Session
;
792 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
796 Conn
= NET_LIST_USER_STRUCT_S (
797 Session
->Conns
.ForwardLink
,
800 ISCSI_CONNECTION_SIGNATURE
802 Tcp4Io
= &Conn
->Tcp4Io
;
804 Status
= gBS
->HandleProtocol (
806 &gEfiDevicePathProtocolGuid
,
809 if (EFI_ERROR (Status
)) {
815 DevicePath
= DuplicateDevicePath (DevicePath
);
816 if (DevicePath
== NULL
) {
820 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
822 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
823 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
824 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
827 DPathNode
->Ipv4
.LocalPort
= 0;
828 DPathNode
->Ipv4
.StaticIpAddress
=
829 (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
832 // Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
833 // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
835 // In new version of IPv4_DEVICE_PATH, structcure length is 27.
837 if (DevicePathNodeLength (&DPathNode
->Ipv4
) == IP4_NODE_LEN_NEW_VERSIONS
) {
840 &DPathNode
->Ipv4
.GatewayIpAddress
,
841 &Session
->ConfigData
.NvData
.Gateway
845 &DPathNode
->Ipv4
.SubnetMask
,
846 &Session
->ConfigData
.NvData
.SubnetMask
853 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
860 Abort the session when the transition from BS to RT is initiated.
862 @param[in] Event The event signaled.
863 @param[in] Context The iSCSI driver data.
867 IScsiOnExitBootService (
872 ISCSI_DRIVER_DATA
*Private
;
874 Private
= (ISCSI_DRIVER_DATA
*) Context
;
875 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
877 IScsiSessionAbort (&Private
->Session
);
881 Tests whether a controller handle is being managed by IScsi driver.
883 This function tests whether the driver specified by DriverBindingHandle is
884 currently managing the controller specified by ControllerHandle. This test
885 is performed by evaluating if the the protocol specified by ProtocolGuid is
886 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
887 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
888 If ProtocolGuid is NULL, then ASSERT().
890 @param ControllerHandle A handle for a controller to test.
891 @param DriverBindingHandle Specifies the driver binding handle for the
893 @param ProtocolGuid Specifies the protocol that the driver specified
894 by DriverBindingHandle opens in its Start()
897 @retval EFI_SUCCESS ControllerHandle is managed by the driver
898 specified by DriverBindingHandle.
899 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
900 specified by DriverBindingHandle.
905 IScsiTestManagedDevice (
906 IN EFI_HANDLE ControllerHandle
,
907 IN EFI_HANDLE DriverBindingHandle
,
908 IN EFI_GUID
*ProtocolGuid
912 VOID
*ManagedInterface
;
913 EFI_HANDLE NicControllerHandle
;
915 ASSERT (ProtocolGuid
!= NULL
);
917 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
918 if (NicControllerHandle
== NULL
) {
919 return EFI_UNSUPPORTED
;
922 Status
= gBS
->OpenProtocol (
924 (EFI_GUID
*) ProtocolGuid
,
928 EFI_OPEN_PROTOCOL_BY_DRIVER
930 if (!EFI_ERROR (Status
)) {
933 (EFI_GUID
*) ProtocolGuid
,
937 return EFI_UNSUPPORTED
;
940 if (Status
!= EFI_ALREADY_STARTED
) {
941 return EFI_UNSUPPORTED
;