2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2014, 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 StrCpy (TempStr
, 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.
593 IScsiCleanDriverData (
594 IN ISCSI_DRIVER_DATA
*Private
597 if (Private
->DevicePath
!= NULL
) {
598 gBS
->UninstallProtocolInterface (
599 Private
->ExtScsiPassThruHandle
,
600 &gEfiDevicePathProtocolGuid
,
604 FreePool (Private
->DevicePath
);
607 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
608 gBS
->UninstallProtocolInterface (
609 Private
->ExtScsiPassThruHandle
,
610 &gEfiExtScsiPassThruProtocolGuid
,
611 &Private
->IScsiExtScsiPassThru
615 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
621 Check wheather the Controller is configured to use DHCP protocol.
623 @param[in] Controller The handle of the controller.
625 @retval TRUE The handle of the controller need the Dhcp protocol.
626 @retval FALSE The handle of the controller does not need the Dhcp protocol.
630 IScsiDhcpIsConfigured (
631 IN EFI_HANDLE Controller
635 EFI_MAC_ADDRESS MacAddress
;
638 CHAR16 MacString
[70];
639 ISCSI_SESSION_CONFIG_NVDATA
*ConfigDataTmp
;
642 // Get the mac string, it's the name of various variable
644 Status
= NetLibGetMacAddress (Controller
, &MacAddress
, &HwAddressSize
);
645 if (EFI_ERROR (Status
)) {
648 VlanId
= NetLibGetVlanId (Controller
);
649 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
652 // Get the normal configuration.
654 Status
= GetVariable2 (
656 &gEfiIScsiInitiatorNameProtocolGuid
,
657 (VOID
**)&ConfigDataTmp
,
660 if (ConfigDataTmp
== NULL
|| EFI_ERROR (Status
)) {
664 if (ConfigDataTmp
->Enabled
&& ConfigDataTmp
->InitiatorInfoFromDhcp
) {
665 FreePool (ConfigDataTmp
);
669 FreePool (ConfigDataTmp
);
674 Get the various configuration data of this iSCSI instance.
676 @param[in] Private The iSCSI driver data.
678 @retval EFI_SUCCESS The configuration of this instance is got.
679 @retval EFI_ABORTED The operation was aborted.
680 @retval Others Other errors as indicated.
684 IN ISCSI_DRIVER_DATA
*Private
688 ISCSI_SESSION
*Session
;
690 EFI_MAC_ADDRESS MacAddress
;
693 CHAR16 MacString
[70];
696 // get the iSCSI Initiator Name
698 Session
= &Private
->Session
;
699 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
700 Status
= gIScsiInitiatorName
.Get (
701 &gIScsiInitiatorName
,
702 &Session
->InitiatorNameLength
,
703 Session
->InitiatorName
705 if (EFI_ERROR (Status
)) {
710 // Get the mac string, it's the name of various variable
712 Status
= NetLibGetMacAddress (Private
->Controller
, &MacAddress
, &HwAddressSize
);
713 ASSERT (Status
== EFI_SUCCESS
);
714 VlanId
= NetLibGetVlanId (Private
->Controller
);
715 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
718 // Get the normal configuration.
720 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
721 Status
= gRT
->GetVariable (
723 &gEfiIScsiInitiatorNameProtocolGuid
,
726 &Session
->ConfigData
.NvData
728 if (EFI_ERROR (Status
)) {
732 if (!Session
->ConfigData
.NvData
.Enabled
) {
736 // Get the CHAP Auth information.
738 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
739 Status
= gRT
->GetVariable (
741 &gIScsiCHAPAuthInfoGuid
,
744 &Session
->AuthData
.AuthConfig
747 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
751 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
758 Get the device path of the iSCSI tcp connection and update it.
760 @param[in] Private The iSCSI driver data.
762 @return The updated device path.
763 @retval NULL Other errors as indicated.
765 EFI_DEVICE_PATH_PROTOCOL
*
766 IScsiGetTcpConnDevicePath (
767 IN ISCSI_DRIVER_DATA
*Private
770 ISCSI_SESSION
*Session
;
771 ISCSI_CONNECTION
*Conn
;
773 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
775 EFI_DEV_PATH
*DPathNode
;
777 Session
= &Private
->Session
;
778 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
782 Conn
= NET_LIST_USER_STRUCT_S (
783 Session
->Conns
.ForwardLink
,
786 ISCSI_CONNECTION_SIGNATURE
788 Tcp4Io
= &Conn
->Tcp4Io
;
790 Status
= gBS
->HandleProtocol (
792 &gEfiDevicePathProtocolGuid
,
795 if (EFI_ERROR (Status
)) {
801 DevicePath
= DuplicateDevicePath (DevicePath
);
802 if (DevicePath
== NULL
) {
806 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
808 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
809 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
810 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
813 DPathNode
->Ipv4
.LocalPort
= 0;
814 DPathNode
->Ipv4
.StaticIpAddress
=
815 (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
818 &DPathNode
->Ipv4
.GatewayIpAddress
,
819 &Session
->ConfigData
.NvData
.Gateway
823 &DPathNode
->Ipv4
.SubnetMask
,
824 &Session
->ConfigData
.NvData
.SubnetMask
830 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
837 Abort the session when the transition from BS to RT is initiated.
839 @param[in] Event The event signaled.
840 @param[in] Context The iSCSI driver data.
844 IScsiOnExitBootService (
849 ISCSI_DRIVER_DATA
*Private
;
851 Private
= (ISCSI_DRIVER_DATA
*) Context
;
852 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
854 IScsiSessionAbort (&Private
->Session
);
858 Tests whether a controller handle is being managed by IScsi driver.
860 This function tests whether the driver specified by DriverBindingHandle is
861 currently managing the controller specified by ControllerHandle. This test
862 is performed by evaluating if the the protocol specified by ProtocolGuid is
863 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
864 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
865 If ProtocolGuid is NULL, then ASSERT().
867 @param ControllerHandle A handle for a controller to test.
868 @param DriverBindingHandle Specifies the driver binding handle for the
870 @param ProtocolGuid Specifies the protocol that the driver specified
871 by DriverBindingHandle opens in its Start()
874 @retval EFI_SUCCESS ControllerHandle is managed by the driver
875 specified by DriverBindingHandle.
876 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
877 specified by DriverBindingHandle.
882 IScsiTestManagedDevice (
883 IN EFI_HANDLE ControllerHandle
,
884 IN EFI_HANDLE DriverBindingHandle
,
885 IN EFI_GUID
*ProtocolGuid
889 VOID
*ManagedInterface
;
890 EFI_HANDLE NicControllerHandle
;
892 ASSERT (ProtocolGuid
!= NULL
);
894 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
895 if (NicControllerHandle
== NULL
) {
896 return EFI_UNSUPPORTED
;
899 Status
= gBS
->OpenProtocol (
901 (EFI_GUID
*) ProtocolGuid
,
905 EFI_OPEN_PROTOCOL_BY_DRIVER
907 if (!EFI_ERROR (Status
)) {
910 (EFI_GUID
*) ProtocolGuid
,
914 return EFI_UNSUPPORTED
;
917 if (Status
!= EFI_ALREADY_STARTED
) {
918 return EFI_UNSUPPORTED
;