3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Miscellaneous routines for iSCSI driver.
22 #include "IScsiImpl.h"
24 STATIC CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
35 Determines if a Unicode character is a hexadecimal digit.
36 The test is case insensitive.
39 Digit - Pointer to byte that receives the value of the hex character.
40 Char - Unicode character to test.
43 TRUE - If the character is a hexadecimal digit.
48 if ((Char
>= L
'0') && (Char
<= L
'9')) {
49 *Digit
= (UINT8
) (Char
- L
'0');
53 if ((Char
>= L
'A') && (Char
<= L
'F')) {
54 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
58 if ((Char
>= L
'a') && (Char
<= L
'f')) {
59 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
76 Removes (trims) specified leading and trailing characters from a string.
80 str - Pointer to the null-terminated string to be trimmed. On return,
81 str will hold the trimmed string.
82 CharC - Character will be trimmed from str.
96 // Trim off the leading and trailing characters c
98 for (p1
= str
; *p1
&& *p1
== CharC
; p1
++) {
118 for (p1
= str
+ StrLen(str
) - 1; p1
>= str
&& *p1
== CharC
; p1
--) {
121 if (p1
!= str
+ StrLen(str
) - 1) {
127 IScsiGetSubnetMaskPrefixLength (
128 IN EFI_IPv4_ADDRESS
*SubnetMask
134 Calculate the prefix length of the IPv4 subnet mask.
138 SubnetMask - The IPv4 subnet mask.
142 The prefix length of the subnet mask.
150 // The SubnetMask is in network byte order.
152 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
157 ReverseMask
= ~ReverseMask
;
159 if (ReverseMask
& (ReverseMask
+ 1)) {
165 while (ReverseMask
!= 0) {
166 ReverseMask
= ReverseMask
>> 1;
170 return (UINT8
) (32 - Len
);
182 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
186 Str - The hexadecimal encoded LUN string.
187 Lun - Storage to return the 64-bit LUN.
191 EFI_SUCCESS - The 64-bit LUN is stored in Lun.
192 EFI_INVALID_PARAMETER - The string is malformatted.
197 CHAR8
*LunUnitStr
[4];
202 NetZeroMem (LunUnitStr
, sizeof (LunUnitStr
));
207 if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
208 return EFI_INVALID_PARAMETER
;
211 while (*Str
!= '\0') {
213 // Legal representations of LUN:
214 // 4752-3A4F-6b7e-2F99,
222 if (*(Str
+ 1) != '\0') {
223 if (!IsHexDigit ((UINT8
*) &Digit
, *(Str
+ 1))) {
224 return EFI_INVALID_PARAMETER
;
227 LunUnitStr
[Index
] = Str
+ 1;
229 } else if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
230 return EFI_INVALID_PARAMETER
;
236 for (Index
= 0; (Index
< 4) && (LunUnitStr
[Index
] != NULL
); Index
++) {
237 if (AsciiStrLen (LunUnitStr
[Index
]) > 4) {
238 return EFI_INVALID_PARAMETER
;
241 Temp
= AsciiStrHexToUintn (LunUnitStr
[Index
]);
242 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Temp
);
249 IScsiLunToUnicodeStr (
257 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
261 Lun - The 64-bit LUN.
262 Str - The storage to return the hexadecimal encoded LUN string.
275 for (Index
= 0; Index
< 4; Index
++) {
277 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
278 StrCpy (TempStr
, L
"0-");
280 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
281 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0xf];
282 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
283 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0xf];
287 StrTrim (TempStr
, L
'0');
290 TempStr
+= StrLen (TempStr
);
293 Str
[StrLen (Str
) - 1] = 0;
295 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
296 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
305 IScsiAsciiStrToUnicodeStr (
307 OUT CHAR16
*Destination
313 Convert the ASCII string into a UNICODE string.
317 Source - The ASCII string.
318 Destination - The storage to return the UNICODE string.
322 Pointer to the UNICODE string.
326 ASSERT (Destination
!= NULL
);
327 ASSERT (Source
!= NULL
);
329 while (*Source
!= '\0') {
330 *(Destination
++) = (CHAR16
) *(Source
++);
339 IScsiUnicodeStrToAsciiStr (
341 OUT CHAR8
*Destination
347 Convert the UNICODE string into an ASCII string.
351 Source - The UNICODE string.
352 Destination - The storage to return the ASCII string.
356 Pointer to the ASCII string.
360 ASSERT (Destination
!= NULL
);
361 ASSERT (Source
!= NULL
);
363 while (*Source
!= '\0') {
365 // If any Unicode characters in Source contain
366 // non-zero value in the upper 8 bits, then ASSERT().
368 ASSERT (*Source
< 0x100);
369 *(Destination
++) = (CHAR8
) *(Source
++);
380 OUT EFI_IPv4_ADDRESS
*Ip
386 Convert the decimal dotted IPv4 address into the binary IPv4 address.
390 Str - The UNICODE string.
391 Ip - The storage to return the ASCII string.
395 EFI_SUCCESS - The binary IP address is returned in Ip.
396 EFI_INVALID_PARAMETER - The IP string is malformatted.
408 return EFI_INVALID_PARAMETER
;
412 while (NET_IS_DIGIT (*Str
)) {
413 Number
= Number
* 10 + (*Str
- '0');
418 return EFI_INVALID_PARAMETER
;
421 Ip
->Addr
[Index
] = (UINT8
) Number
;
423 if ((*Str
!= '\0') && (*Str
!= '.')) {
425 // The current character should be either the NULL terminator or
426 // the dot delimiter.
428 return EFI_INVALID_PARAMETER
;
433 // Skip the delimiter.
442 return EFI_INVALID_PARAMETER
;
450 IN EFI_MAC_ADDRESS
*Mac
,
458 Convert the mac address into a hexadecimal encoded "-" seperated string.
462 Mac - The mac address.
463 Len - Length in bytes of the mac address.
464 Str - The storage to return the mac string.
474 for (Index
= 0; Index
< Len
; Index
++) {
475 Str
[3 * Index
] = NibbleToHexChar ((UINT8
) (Mac
->Addr
[Index
] >> 4));
476 Str
[3 * Index
+ 1] = NibbleToHexChar (Mac
->Addr
[Index
]);
477 Str
[3 * Index
+ 2] = L
'-';
480 Str
[3 * Index
- 1] = L
'\0';
487 IN OUT CHAR8
*HexStr
,
488 IN OUT UINT32
*HexLength
494 Convert the binary encoded buffer into a hexadecimal encoded string.
498 BinBuffer - The buffer containing the binary data.
499 BinLength - Length of the binary buffer.
500 HexStr - Pointer to the string.
501 HexLength - The length of the string.
505 EFI_SUCCESS - The binary data is converted to the hexadecimal string
506 and the length of the string is updated.
507 EFI_BUFFER_TOO_SMALL - The string is too small.
513 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
514 return EFI_INVALID_PARAMETER
;
517 if (((*HexLength
) - 3) < BinLength
* 2) {
518 *HexLength
= BinLength
* 2 + 3;
519 return EFI_BUFFER_TOO_SMALL
;
522 *HexLength
= BinLength
* 2 + 3;
524 // Prefix for Hex String
529 for (Index
= 0; Index
< BinLength
; Index
++) {
530 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
531 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
534 HexStr
[Index
* 2 + 2] = '\0';
541 IN OUT UINT8
*BinBuffer
,
542 IN OUT UINT32
*BinLength
,
549 Convert the hexadecimal string into a binary encoded buffer.
553 BinBuffer - The binary buffer.
554 BinLength - Length of the binary buffer.
555 HexStr - The hexadecimal string.
559 EFI_SUCCESS - The hexadecimal string is converted into a binary
561 EFI_BUFFER_TOO_SMALL - The binary buffer is too small to hold the converted data.s
572 // Find out how many hex characters the string has.
575 if ((HexBuf
[0] == '0') && ((HexBuf
[1] == 'x') || (HexBuf
[1] == 'X'))) {
579 for (Index
= 0, HexCount
= 0; IsHexDigit (&Digit
, HexBuf
[Index
]); Index
++, HexCount
++)
587 // Test if buffer is passed enough.
589 if (((HexCount
+ 1) / 2) > *BinLength
) {
590 *BinLength
= (HexCount
+ 1) / 2;
591 return EFI_BUFFER_TOO_SMALL
;
594 *BinLength
= (HexCount
+ 1) / 2;
596 for (Index
= 0; Index
< HexCount
; Index
++) {
598 IsHexDigit (&Digit
, HexBuf
[HexCount
- 1 - Index
]);
600 if ((Index
& 1) == 0) {
603 Byte
= BinBuffer
[*BinLength
- 1 - Index
/ 2];
605 Byte
= (UINT8
) (Byte
| (Digit
<< 4));
608 BinBuffer
[*BinLength
- 1 - Index
/ 2] = Byte
;
623 Generate random numbers.
627 Rand - The buffer to contain random numbers.
628 RandLength - The length of the Rand buffer.
638 while (RandLength
> 0) {
639 Random
= NET_RANDOM (NetRandomInitSeed ());
640 *Rand
++ = (UINT8
) (Random
);
646 IScsiCreateDriverData (
648 IN EFI_HANDLE Controller
654 Create the iSCSI driver data..
658 Image - The handle of the driver image.
659 Controller - The handle of the controller.
663 The iSCSI driver data created.
667 ISCSI_DRIVER_DATA
*Private
;
670 Private
= NetAllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
671 if (Private
== NULL
) {
675 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
676 Private
->Image
= Image
;
677 Private
->Controller
= Controller
;
680 // Create an event to be signal when the BS to RT transition is triggerd so
681 // as to abort the iSCSI session.
683 Status
= gBS
->CreateEvent (
684 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES
,
686 IScsiOnExitBootService
,
688 &Private
->ExitBootServiceEvent
690 if (EFI_ERROR (Status
)) {
691 NetFreePool (Private
);
695 NetCopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
698 // 0 is designated to the TargetId, so use another value for the AdapterId.
700 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
701 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
702 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
703 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
706 // Install the Ext SCSI PASS THRU protocol.
708 Status
= gBS
->InstallProtocolInterface (
709 &Private
->ExtScsiPassThruHandle
,
710 &gEfiExtScsiPassThruProtocolGuid
,
711 EFI_NATIVE_INTERFACE
,
712 &Private
->IScsiExtScsiPassThru
714 if (EFI_ERROR (Status
)) {
715 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
716 NetFreePool (Private
);
721 IScsiSessionInit (&Private
->Session
, FALSE
);
727 IScsiCleanDriverData (
728 IN ISCSI_DRIVER_DATA
*Private
734 Clean the iSCSI driver data.
738 Private - The iSCSI driver data.
746 if (Private
->DevicePath
!= NULL
) {
747 gBS
->UninstallProtocolInterface (
748 Private
->ExtScsiPassThruHandle
,
749 &gEfiDevicePathProtocolGuid
,
753 NetFreePool (Private
->DevicePath
);
756 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
757 gBS
->UninstallProtocolInterface (
758 Private
->ExtScsiPassThruHandle
,
759 &gEfiExtScsiPassThruProtocolGuid
,
760 &Private
->IScsiExtScsiPassThru
764 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
766 NetFreePool (Private
);
771 IN ISCSI_DRIVER_DATA
*Private
777 Get the various configuration data of this iSCSI instance.
781 Private - The iSCSI driver data.
785 EFI_SUCCESS - The configuration of this instance is got.
786 EFI_NOT_FOUND - This iSCSI instance is not configured yet.
791 ISCSI_SESSION
*Session
;
793 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
794 EFI_SIMPLE_NETWORK_MODE
*Mode
;
795 CHAR16 MacString
[65];
798 // get the iSCSI Initiator Name
800 Session
= &Private
->Session
;
801 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
802 Status
= gIScsiInitiatorName
.Get (
803 &gIScsiInitiatorName
,
804 &Session
->InitiatorNameLength
,
805 Session
->InitiatorName
807 if (EFI_ERROR (Status
)) {
811 Status
= gBS
->HandleProtocol (
813 &gEfiSimpleNetworkProtocolGuid
,
816 if (EFI_ERROR (Status
)) {
823 // Get the mac string, it's the name of various variable
825 IScsiMacAddrToStr (&Mode
->PermanentAddress
, Mode
->HwAddressSize
, MacString
);
828 // Get the normal configuration.
830 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
831 Status
= gRT
->GetVariable (
833 &gEfiIScsiInitiatorNameProtocolGuid
,
836 &Session
->ConfigData
.NvData
838 if (EFI_ERROR (Status
)) {
842 if (!Session
->ConfigData
.NvData
.Enabled
) {
846 // Get the CHAP Auth information.
848 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
849 Status
= gRT
->GetVariable (
851 &mIScsiCHAPAuthInfoGuid
,
854 &Session
->AuthData
.AuthConfig
857 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
861 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
867 EFI_DEVICE_PATH_PROTOCOL
*
868 IScsiGetTcpConnDevicePath (
869 IN ISCSI_DRIVER_DATA
*Private
875 Get the device path of the iSCSI tcp connection and update it.
879 Private - The iSCSI driver data.
883 The updated device path.
887 ISCSI_SESSION
*Session
;
888 ISCSI_CONNECTION
*Conn
;
890 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
892 EFI_DEV_PATH
*DPathNode
;
894 Session
= &Private
->Session
;
895 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
899 Conn
= NET_LIST_USER_STRUCT_S (
900 Session
->Conns
.ForwardLink
,
903 ISCSI_CONNECTION_SIGNATURE
905 Tcp4Io
= &Conn
->Tcp4Io
;
907 Status
= gBS
->HandleProtocol (
909 &gEfiDevicePathProtocolGuid
,
912 if (EFI_ERROR (Status
)) {
918 DevicePath
= DuplicateDevicePath (DevicePath
);
920 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
922 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
923 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
924 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
927 DPathNode
->Ipv4
.LocalPort
= 0;
928 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
932 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
940 IScsiOnExitBootService (
948 Abort the session when the transition from BS to RT is initiated.
952 Event - The event signaled.
953 Context - The iSCSI driver data.
961 ISCSI_DRIVER_DATA
*Private
;
963 Private
= (ISCSI_DRIVER_DATA
*) Context
;
964 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
966 IScsiSessionAbort (&Private
->Session
);