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 Str
[StrLen (Str
) - 1] = 0;
224 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
225 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
234 Convert the ASCII string into a UNICODE string.
236 @param[in] Source The ASCII string.
237 @param[out] Destination The storage to return the UNICODE string.
239 @return CHAR16 * Pointer to the UNICODE string.
242 IScsiAsciiStrToUnicodeStr (
244 OUT CHAR16
*Destination
247 ASSERT (Destination
!= NULL
);
248 ASSERT (Source
!= NULL
);
250 while (*Source
!= '\0') {
251 *(Destination
++) = (CHAR16
) *(Source
++);
260 Convert the UNICODE string into an ASCII string.
262 @param[in] Source The UNICODE string.
263 @param[out] Destination The storage to return the ASCII string.
265 @return CHAR8 * Pointer to the ASCII string.
268 IScsiUnicodeStrToAsciiStr (
270 OUT CHAR8
*Destination
273 ASSERT (Destination
!= NULL
);
274 ASSERT (Source
!= NULL
);
276 while (*Source
!= '\0') {
278 // If any Unicode characters in Source contain
279 // non-zero value in the upper 8 bits, then ASSERT().
281 ASSERT (*Source
< 0x100);
282 *(Destination
++) = (CHAR8
) *(Source
++);
291 Convert the decimal dotted IPv4 address into the binary IPv4 address.
293 @param[in] Str The UNICODE string.
294 @param[out] Ip The storage to return the ASCII string.
296 @retval EFI_SUCCESS The binary IP address is returned in Ip.
297 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
302 OUT EFI_IPv4_ADDRESS
*Ip
313 return EFI_INVALID_PARAMETER
;
317 while (NET_IS_DIGIT (*Str
)) {
318 Number
= Number
* 10 + (*Str
- '0');
323 return EFI_INVALID_PARAMETER
;
326 Ip
->Addr
[Index
] = (UINT8
) Number
;
328 if ((*Str
!= '\0') && (*Str
!= '.')) {
330 // The current character should be either the NULL terminator or
331 // the dot delimiter.
333 return EFI_INVALID_PARAMETER
;
338 // Skip the delimiter.
347 return EFI_INVALID_PARAMETER
;
354 Convert the mac address into a hexadecimal encoded "-" seperated string.
356 @param[in] Mac The mac address.
357 @param[in] Len Length in bytes of the mac address.
358 @param[in] VlanId VLAN ID of the network device.
359 @param[out] Str The storage to return the mac string.
363 IN EFI_MAC_ADDRESS
*Mac
,
372 for (Index
= 0; Index
< Len
; Index
++) {
373 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
374 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
375 Str
[3 * Index
+ 2] = L
'-';
378 String
= &Str
[3 * Index
- 1] ;
380 String
+= UnicodeSPrint (String
, 6 * sizeof (CHAR16
), L
"\\%04x", (UINTN
) VlanId
);
387 Convert the binary encoded buffer into a hexadecimal encoded string.
389 @param[in] BinBuffer The buffer containing the binary data.
390 @param[in] BinLength Length of the binary buffer.
391 @param[in, out] HexStr Pointer to the string.
392 @param[in, out] HexLength The length of the string.
394 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
395 and the length of the string is updated.
396 @retval EFI_BUFFER_TOO_SMALL The string is too small.
397 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
403 IN OUT CHAR8
*HexStr
,
404 IN OUT UINT32
*HexLength
409 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
410 return EFI_INVALID_PARAMETER
;
413 if (((*HexLength
) - 3) < BinLength
* 2) {
414 *HexLength
= BinLength
* 2 + 3;
415 return EFI_BUFFER_TOO_SMALL
;
418 *HexLength
= BinLength
* 2 + 3;
420 // Prefix for Hex String
425 for (Index
= 0; Index
< BinLength
; Index
++) {
426 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
427 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0x0F];
430 HexStr
[Index
* 2 + 2] = '\0';
436 Convert the hexadecimal string into a binary encoded buffer.
438 @param[in, out] BinBuffer The binary buffer.
439 @param[in, out] BinLength Length of the binary buffer.
440 @param[in] HexStr The hexadecimal string.
442 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
444 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
448 IN OUT UINT8
*BinBuffer
,
449 IN OUT UINT32
*BinLength
,
458 ZeroMem (TemStr
, sizeof (TemStr
));
461 // Find out how many hex characters the string has.
463 if ((HexStr
[0] == '0') && ((HexStr
[1] == 'x') || (HexStr
[1] == 'X'))) {
467 Length
= AsciiStrLen (HexStr
);
469 for (Index
= 0; Index
< Length
; Index
++) {
470 TemStr
[0] = HexStr
[Index
];
471 Digit
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
472 if (Digit
== 0 && TemStr
[0] != '0') {
478 if ((Index
& 1) == 0) {
479 BinBuffer
[Index
/2] = Digit
;
481 BinBuffer
[Index
/2] = (UINT8
) ((BinBuffer
[Index
/2] << 4) + Digit
);
485 *BinLength
= (UINT32
) ((Index
+ 1)/2);
491 Generate random numbers.
493 @param[in, out] Rand The buffer to contain random numbers.
494 @param[in] RandLength The length of the Rand buffer.
504 while (RandLength
> 0) {
505 Random
= NET_RANDOM (NetRandomInitSeed ());
506 *Rand
++ = (UINT8
) (Random
);
512 Create the iSCSI driver data..
514 @param[in] Image The handle of the driver image.
515 @param[in] Controller The handle of the controller.
517 @return The iSCSI driver data created.
518 @retval NULL Other errors as indicated.
521 IScsiCreateDriverData (
523 IN EFI_HANDLE Controller
526 ISCSI_DRIVER_DATA
*Private
;
529 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
530 if (Private
== NULL
) {
534 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
535 Private
->Image
= Image
;
536 Private
->Controller
= Controller
;
539 // Create an event to be signal when the BS to RT transition is triggerd so
540 // as to abort the iSCSI session.
542 Status
= gBS
->CreateEventEx (
545 IScsiOnExitBootService
,
547 &gEfiEventExitBootServicesGuid
,
548 &Private
->ExitBootServiceEvent
550 if (EFI_ERROR (Status
)) {
555 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
558 // 0 is designated to the TargetId, so use another value for the AdapterId.
560 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
561 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
562 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
563 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
566 // Install the Ext SCSI PASS THRU protocol.
568 Status
= gBS
->InstallProtocolInterface (
569 &Private
->ExtScsiPassThruHandle
,
570 &gEfiExtScsiPassThruProtocolGuid
,
571 EFI_NATIVE_INTERFACE
,
572 &Private
->IScsiExtScsiPassThru
574 if (EFI_ERROR (Status
)) {
575 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
581 IScsiSessionInit (&Private
->Session
, FALSE
);
587 Clean the iSCSI driver data.
589 @param[in] Private The iSCSI driver data.
592 IScsiCleanDriverData (
593 IN ISCSI_DRIVER_DATA
*Private
596 if (Private
->DevicePath
!= NULL
) {
597 gBS
->UninstallProtocolInterface (
598 Private
->ExtScsiPassThruHandle
,
599 &gEfiDevicePathProtocolGuid
,
603 FreePool (Private
->DevicePath
);
606 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
607 gBS
->UninstallProtocolInterface (
608 Private
->ExtScsiPassThruHandle
,
609 &gEfiExtScsiPassThruProtocolGuid
,
610 &Private
->IScsiExtScsiPassThru
614 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
620 Check wheather the Controller is configured to use DHCP protocol.
622 @param[in] Controller The handle of the controller.
624 @retval TRUE The handle of the controller need the Dhcp protocol.
625 @retval FALSE The handle of the controller does not need the Dhcp protocol.
629 IScsiDhcpIsConfigured (
630 IN EFI_HANDLE Controller
634 EFI_MAC_ADDRESS MacAddress
;
637 CHAR16 MacString
[70];
638 ISCSI_SESSION_CONFIG_NVDATA
*ConfigDataTmp
;
641 // Get the mac string, it's the name of various variable
643 Status
= NetLibGetMacAddress (Controller
, &MacAddress
, &HwAddressSize
);
644 if (EFI_ERROR (Status
)) {
647 VlanId
= NetLibGetVlanId (Controller
);
648 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
651 // Get the normal configuration.
653 Status
= GetVariable2 (
655 &gEfiIScsiInitiatorNameProtocolGuid
,
656 (VOID
**)&ConfigDataTmp
,
659 if (ConfigDataTmp
== NULL
|| EFI_ERROR (Status
)) {
663 if (ConfigDataTmp
->Enabled
&& ConfigDataTmp
->InitiatorInfoFromDhcp
) {
664 FreePool (ConfigDataTmp
);
668 FreePool (ConfigDataTmp
);
673 Get the various configuration data of this iSCSI instance.
675 @param[in] Private The iSCSI driver data.
677 @retval EFI_SUCCESS The configuration of this instance is got.
678 @retval EFI_ABORTED The operation was aborted.
679 @retval Others Other errors as indicated.
683 IN ISCSI_DRIVER_DATA
*Private
687 ISCSI_SESSION
*Session
;
689 EFI_MAC_ADDRESS MacAddress
;
692 CHAR16 MacString
[70];
695 // get the iSCSI Initiator Name
697 Session
= &Private
->Session
;
698 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
699 Status
= gIScsiInitiatorName
.Get (
700 &gIScsiInitiatorName
,
701 &Session
->InitiatorNameLength
,
702 Session
->InitiatorName
704 if (EFI_ERROR (Status
)) {
709 // Get the mac string, it's the name of various variable
711 Status
= NetLibGetMacAddress (Private
->Controller
, &MacAddress
, &HwAddressSize
);
712 ASSERT (Status
== EFI_SUCCESS
);
713 VlanId
= NetLibGetVlanId (Private
->Controller
);
714 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
717 // Get the normal configuration.
719 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
720 Status
= gRT
->GetVariable (
722 &gEfiIScsiInitiatorNameProtocolGuid
,
725 &Session
->ConfigData
.NvData
727 if (EFI_ERROR (Status
)) {
731 if (!Session
->ConfigData
.NvData
.Enabled
) {
735 // Get the CHAP Auth information.
737 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
738 Status
= gRT
->GetVariable (
740 &gIScsiCHAPAuthInfoGuid
,
743 &Session
->AuthData
.AuthConfig
746 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
750 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
757 Get the device path of the iSCSI tcp connection and update it.
759 @param[in] Private The iSCSI driver data.
761 @return The updated device path.
762 @retval NULL Other errors as indicated.
764 EFI_DEVICE_PATH_PROTOCOL
*
765 IScsiGetTcpConnDevicePath (
766 IN ISCSI_DRIVER_DATA
*Private
769 ISCSI_SESSION
*Session
;
770 ISCSI_CONNECTION
*Conn
;
772 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
774 EFI_DEV_PATH
*DPathNode
;
776 Session
= &Private
->Session
;
777 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
781 Conn
= NET_LIST_USER_STRUCT_S (
782 Session
->Conns
.ForwardLink
,
785 ISCSI_CONNECTION_SIGNATURE
787 Tcp4Io
= &Conn
->Tcp4Io
;
789 Status
= gBS
->HandleProtocol (
791 &gEfiDevicePathProtocolGuid
,
794 if (EFI_ERROR (Status
)) {
800 DevicePath
= DuplicateDevicePath (DevicePath
);
801 if (DevicePath
== NULL
) {
805 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
807 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
808 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
809 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
812 DPathNode
->Ipv4
.LocalPort
= 0;
813 DPathNode
->Ipv4
.StaticIpAddress
=
814 (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
817 &DPathNode
->Ipv4
.GatewayIpAddress
,
818 &Session
->ConfigData
.NvData
.Gateway
822 &DPathNode
->Ipv4
.SubnetMask
,
823 &Session
->ConfigData
.NvData
.SubnetMask
829 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
836 Abort the session when the transition from BS to RT is initiated.
838 @param[in] Event The event signaled.
839 @param[in] Context The iSCSI driver data.
843 IScsiOnExitBootService (
848 ISCSI_DRIVER_DATA
*Private
;
850 Private
= (ISCSI_DRIVER_DATA
*) Context
;
851 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
853 IScsiSessionAbort (&Private
->Session
);
857 Tests whether a controller handle is being managed by IScsi driver.
859 This function tests whether the driver specified by DriverBindingHandle is
860 currently managing the controller specified by ControllerHandle. This test
861 is performed by evaluating if the the protocol specified by ProtocolGuid is
862 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
863 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
864 If ProtocolGuid is NULL, then ASSERT().
866 @param ControllerHandle A handle for a controller to test.
867 @param DriverBindingHandle Specifies the driver binding handle for the
869 @param ProtocolGuid Specifies the protocol that the driver specified
870 by DriverBindingHandle opens in its Start()
873 @retval EFI_SUCCESS ControllerHandle is managed by the driver
874 specified by DriverBindingHandle.
875 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
876 specified by DriverBindingHandle.
881 IScsiTestManagedDevice (
882 IN EFI_HANDLE ControllerHandle
,
883 IN EFI_HANDLE DriverBindingHandle
,
884 IN EFI_GUID
*ProtocolGuid
888 VOID
*ManagedInterface
;
889 EFI_HANDLE NicControllerHandle
;
891 ASSERT (ProtocolGuid
!= NULL
);
893 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
894 if (NicControllerHandle
== NULL
) {
895 return EFI_UNSUPPORTED
;
898 Status
= gBS
->OpenProtocol (
900 (EFI_GUID
*) ProtocolGuid
,
904 EFI_OPEN_PROTOCOL_BY_DRIVER
906 if (!EFI_ERROR (Status
)) {
909 (EFI_GUID
*) ProtocolGuid
,
913 return EFI_UNSUPPORTED
;
916 if (Status
!= EFI_ALREADY_STARTED
) {
917 return EFI_UNSUPPORTED
;