2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2013, 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 (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
);