2025-11-28 00:35:46 +09:00

5995 lines
173 KiB
C

//***************************************************************************
//
// iscsicli.c
//
// Module: iscsi discovery command line tool
//
// Purpose: Contains iscsi discovery command line tool
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//***************************************************************************
#define WIN32_LEAN_AND_MEAN
#include <initguid.h>
#include <windows.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <tchar.h>
#include "iscsierr.h"
#include "iscsidsc.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <setupapi.h>
#include <strsafe.h>
//
// This struct carries around information about a volume including the
// disk extents that comprise the volume and the volume path names
//
typedef struct
{
union
{
VOLUME_DISK_EXTENTS VolumeDiskExtents;
UCHAR VolumeDiskExtentsBuffer[sizeof(VOLUME_DISK_EXTENTS) + 1024 * sizeof(DISK_EXTENT)];
};
TCHAR VolumePathNames[1];
} VOLUMEMOREINFO, *PVOLUMEMOREINFO;
typedef struct
{
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
SP_DEVINFO_DATA DeviceInfoData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
PVOID MoreInfo;
} DEVICEINTERFACEENTRY, *PDEVICEINTERFACEENTRY;
typedef ISDSC_STATUS (*ENUMDEVICEINTERFACECALLBACK)(
IN PVOID Context,
IN LPGUID Guid,
IN HDEVINFO DevInfo,
IN OUT PDEVICEINTERFACEENTRY DevEntry
);
#define OffsetToPtr(Base, Offset) ((PBYTE)((PBYTE)(Base) + (Offset)))
#define Alloc(size) malloc(size)
#define Free(p) free(p)
void Usage(ULONG Code)
{
if (Code == 0)
{
#ifdef UNICODE
printf("iscsicli\n");
printf("\n");
#endif
}
if ((Code == 0) || (Code == 1))
{
printf("iscsicli AddTarget <TargetName> <TargetAlias> <TargetPortalAddress>\n");
printf(" <TargetPortalSocket> <Target flags>\n");
printf(" <Persist> <Login Flags> <Header Digest> <Data Digest> \n");
printf(" <Max Connections> <DefaultTime2Wait>\n");
printf(" <DefaultTime2Retain> <Username> <Password> <AuthType>\n");
printf(" <Mapping Count> <Target Lun> <OS Bus> <Os Target> \n");
printf(" <OS Lun> ...\n");
printf("\n");
}
if ((Code == 0) || (Code == 2))
{
printf("iscsicli RemoveTarget <TargetName> \n");
printf("\n");
}
if ((Code == 0) || (Code == 3))
{
printf("iscsicli AddTargetPortal <TargetPortalAddress> <TargetPortalSocket> \n");
printf(" [HBA Name] [Port Number]\n");
printf(" <Security Flags>\n");
printf(" <Login Flags> <Header Digest> <Data Digest> \n");
printf(" <Max Connections> <DefaultTime2Wait>\n");
printf(" <DefaultTime2Retain> <Username> <Password> <AuthType>\n");
printf("\n");
}
if ((Code == 0) || (Code == 4))
{
printf("iscsicli RemoveTargetPortal <TargetPortalAddress> <TargetPortalSocket> [HBA Name] [Port Number]\n");
printf("\n");
}
if ((Code == 0) || (Code == 5))
{
printf("iscsicli RefreshTargetPortal <TargetPortalAddress> <TargetPortalSocket> [HBA Name] [Port Number]\n");
printf("\n");
}
if ((Code == 0) || (Code == 6))
{
printf("iscsicli ListTargets [ForceUpdate]\n");
printf("\n");
}
if ((Code == 0) || (Code == 7))
{
printf("iscsicli ListTargetPortals\n");
printf("\n");
}
if ((Code == 0) || (Code == 8))
{
printf("iscsicli TargetInfo <TargetName> [Discovery Mechanism]\n");
printf("\n");
}
if ((Code == 0) || (Code == 9))
{
printf("iscsicli LoginTarget <TargetName> <ReportToPNP>\n");
printf(" <TargetPortalAddress> <TargetPortalSocket>\n");
printf(" <InitiatorInstance> <Port number> <Security Flags>\n");
printf(" <Login Flags> <Header Digest> <Data Digest> \n");
printf(" <Max Connections> <DefaultTime2Wait>\n");
printf(" <DefaultTime2Retain> <Username> <Password> <AuthType> <Key>\n");
printf(" <Mapping Count> <Target Lun> <OS Bus> <Os Target> \n");
printf(" <OS Lun> ...\n");
printf("\n");
}
if ((Code == 0) || (Code == 10))
{
printf("iscsicli LogoutTarget <SessionId>\n");
printf("\n");
}
if ((Code == 0) || (Code == 11))
{
printf("iscsicli PersistentLoginTarget <TargetName> <ReportToPNP>\n");
printf(" <TargetPortalAddress> <TargetPortalSocket>\n");
printf(" <InitiatorInstance> <Port number> <Security Flags>\n");
printf(" <Login Flags> <Header Digest> <Data Digest> \n");
printf(" <Max Connections> <DefaultTime2Wait>\n");
printf(" <DefaultTime2Retain> <Username> <Password> <AuthType> <Key>\n");
printf(" <Mapping Count> <Target Lun> <OS Bus> <Os Target> \n");
printf(" <OS Lun> ...\n");
printf("\n");
}
if ((Code == 0) || (Code == 12))
{
printf("iscsicli ListPersistentTargets\n");
printf("\n");
}
if ((Code == 0) || (Code == 13))
{
printf("iscsicli RemovePersistentTarget <Initiator Name> <TargetName> \n");
printf(" <Port Number> \n");
printf(" <Target Portal Address> \n");
printf(" <Target Portal Socket> \n");
printf("\n");
}
if ((Code == 0) || (Code == 14))
{
printf("iscsicli AddConnection <SessionId> <Initiator Instance>\n");
printf(" <Port Number> <Target Portal Address>\n");
printf(" <Target Portal Socket> <Security Flags>\n");
printf(" <Login Flags> <Header Digest> <Data Digest> \n");
printf(" <Max Connections> <DefaultTime2Wait>\n");
printf(" <DefaultTime2Retain> <Username> <Password> <AuthType> <Key>\n");
printf("\n");
}
if ((Code == 0) || (Code == 15))
{
printf("iscsicli RemoveConnection <SessionId> <ConnectionId> \n");
printf("\n");
}
if ((Code == 0) || (Code == 16))
{
printf("iscsicli ScsiInquiry <SessionId> <LUN> <EvpdCmddt> <PageCode>\n");
printf("\n");
}
if ((Code == 0) || (Code == 17))
{
printf("iscsicli ReadCapacity <SessionId> <LUN>\n");
printf("\n");
}
if ((Code == 0) || (Code == 18))
{
printf("iscsicli ReportLUNs <SessionId>\n");
printf("\n");
}
if ((Code == 0) || (Code == 19))
{
printf("iscsicli ReportTargetMappings\n");
printf("\n");
}
if ((Code == 0) || (Code == 20))
{
printf("iscsicli ListInitiators\n");
printf("\n");
}
if ((Code == 0) || (Code == 21))
{
printf("iscsicli AddiSNSServer <iSNS Server Address>\n");
printf("\n");
}
if ((Code == 0) || (Code == 22))
{
printf("iscsicli RemoveiSNSServer <iSNS Server Address>\n");
printf("\n");
}
if ((Code == 0) || (Code == 23))
{
printf("iscsicli RefreshiSNSServer <iSNS Server Address>\n");
printf("\n");
}
if ((Code == 0) || (Code == 24))
{
printf("iscsicli ListiSNSServers\n");
printf("\n");
}
if ((Code == 0) || (Code == 25))
{
printf("iscsicli NodeName <node name>\n");
printf("\n");
}
if ((Code == 0) || (Code == 26))
{
printf("iscsicli SessionList <Show Session Info>\n");
printf("\n");
}
if ((Code == 0) || (Code == 27))
{
printf("iscsicli CHAPSecret <chap secret>\n");
printf("\n");
}
if ((Code == 0) || (Code == 28))
{
printf("iscsicli TunnelAddr <Initiator Name> <InitiatorPort> <Destination Address> <Tunnel Address> <Persist>\n");
printf("\n");
}
if ((Code == 0) || (Code == 29))
{
printf("iscsicli GroupKey <Key> <Persist>\n");
printf("\n");
}
if ((Code == 0) || (Code == 31))
{
printf("iscsicli BindPersistentVolumes\n\n");
printf("iscsicli BindPersistentDevices\n");
printf("\n");
}
if ((Code == 0) || (Code == 37))
{
printf("iscsicli ReportPersistentDevices\n");
printf("\n");
}
if ((Code == 0) || (Code == 38))
{
printf("iscsicli AddPersistentDevice <Volume or Device Path>\n");
printf("\n");
}
if ((Code == 0) || (Code == 39))
{
printf("iscsicli RemovePersistentDevice <Volume or Device Path>\n");
printf("\n");
}
if ((Code == 0) || (Code == 40))
{
printf("iscsicli ClearPersistentDevices\n");
printf("\n");
}
if ((Code == 0) || (Code == 42))
{
printf("iscsicli GetPSKey <Initiator Name> <initiator Port> <Id Type> <Id>\n");
printf("\n");
}
if ((Code == 0) || (Code == 30))
{
printf("iscsicli PSKey <Initiator Name> <initiator Port> <Security Flags> <Id Type> <Id> <Key> <persist>\n");
printf("\n");
}
if (Code == 0)
{
printf("Quick Commands\n\n");
}
if ((Code == 0) || (Code == 33))
{
printf("iscsicli QLoginTarget <TargetName> [CHAP Username] [CHAP Password]\n");
printf("\n");
}
if ((Code == 0) || (Code == 34))
{
printf("iscsicli QAddTarget <TargetName> <TargetPortalAddress>\n");
printf("\n");
}
if ((Code == 0) || (Code == 35))
{
printf("iscsicli QAddTargetPortal <TargetPortalAddress>\n");
printf(" [CHAP Username] [CHAP Password]\n");
printf("\n");
}
if ((Code == 0) || (Code == 36))
{
printf("iscsicli QAddConnection <SessionId> <Initiator Instance>\n");
printf(" <Target Portal Address>\n");
printf(" [CHAP Username] [CHAP Password]\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 1) ||
(Code == 9) ||
(Code == 11))
{
printf("Target Mappings:\n");
printf(" <Target Lun> is the LUN value the target uses to expose the LUN.\n");
printf(" It must be in the form 0x0123456789abcdef\n");
printf(" <OS Bus> is the bus number the OS should use to surface the LUN\n");
printf(" <OS Target> is the target number the OS should use to surface the LUN\n");
printf(" <OS LUN> is the LUN number the OS should use to surface the LUN\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 30) ||
(Code == 42))
{
printf("Payload Id Type:\n");
printf(" ID_IPV4_ADDR is 1 - Id format is 1.2.3.4\n");
printf(" ID_FQDN is 2 - Id format is ComputerName\n");
printf(" ID_IPV6_ADDR is 5 - Id form is IPv6 Address\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 3) ||
(Code == 9) ||
(Code == 11) ||
(Code == 14) ||
(Code == 30))
{
printf("Security Flags:\n");
printf(" TunnelMode is 0x00000040\n");
printf(" TransportMode is 0x00000020\n");
printf(" PFS Enabled is 0x00000010\n");
printf(" Aggressive Mode is 0x00000008\n");
printf(" Main mode is 0x00000004\n");
printf(" IPSEC/IKE Enabled is 0x00000002\n");
printf(" Valid Flags is 0x00000001\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 1) ||
(Code == 3) ||
(Code == 9) ||
(Code == 11) ||
(Code == 14))
{
printf("Login Flags:\n");
printf(" ISCSI_LOGIN_FLAG_REQUIRE_IPSEC 0x00000001\n");
printf(" IPsec is required for the operation\n\n");
printf(" ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED 0x00000002\n");
printf(" Multipathing is enabled for the target on this initiator\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 1) ||
(Code == 3) ||
(Code == 9) ||
(Code == 11) ||
(Code == 14))
{
printf("AuthType:\n");
printf(" ISCSI_NO_AUTH_TYPE = 0,\n");
printf(" No iSCSI in-band authenticiation is used\n\n");
printf(" ISCSI_CHAP_AUTH_TYPE = 1,\n");
printf(" One way CHAP (Target authenticates initiator is used)\n\n");
printf(" ISCSI_MUTUAL_CHAP_AUTH_TYPE = 2\n");
printf(" Mutual CHAP (Target and Initiator authenticate each other is used)\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 1))
{
printf("Target Flags:\n");
printf(" ISCSI_TARGET_FLAG_HIDE_STATIC_TARGET 0x00000002\n");
printf(" If this flag is set then the target will never be reported unless it\n");
printf(" is also discovered dynamically.\n\n");
printf(" ISCSI_TARGET_FLAG_MERGE_TARGET_INFORMATION 0x00000004\n");
printf(" If this flag is set then the target information passed will be\n");
printf(" merged with any target information already statically configured for\n");
printf(" the target\n");
printf("\n");
}
if ((Code == 0) ||
(Code == 1) ||
(Code == 3) ||
(Code == 9) ||
(Code == 11) ||
(Code == 14) ||
(Code == 27) ||
(Code == 30) ||
(Code == 33) ||
(Code == 35) ||
(Code == 36))
{
printf("CHAP secrets, CHAP passwords and IPSEC preshared keys can be specified as\n");
printf("a text string or as a sequence of hexadecimal values. The value specified on\n");
printf("the command line is always considered a string unless the first two characters\n");
printf("0x in which case it is considered a hexadecimal value.\n");
printf("\n");
printf("For example 0x12345678 specifies a 4 byte secret\n");
printf("\n");
}
printf("All numerical values are assumed decimal unless preceeded by 0x. If\n");
printf("preceeded by 0x then value is assumed to be hex\n");
printf("\n");
if (Code == 0)
{
#ifdef UNICODE
printf("iscsicli can also be run in command line mode where iscsicli commands\n");
printf("can be entered directly from the console. To enter command line\n");
printf("mode, just run iscsicli without any parameters\n");
printf("\n");
#endif
}
}
PTCHAR GetiSCSIMessageText(
__out_ecount(MessageLen) PTCHAR Message,
ULONG MessageLen,
ISDSC_STATUS Status
)
{
ULONG d;
HRESULT hr;
//
// first check for os error code
//
d = FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(TEXT("iscsidsc.dll")),
Status,
0, // langid
Message,
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL);
if (d == 0)
{
#ifdef UNICODE
hr = StringCchPrintfW(Message,
MessageLen,
L"Status: 0x%x",
Status);
#else
hr = StringCchPrintfA(Message, MessageLen, "Status: 0x%x", Status);
#endif
}
return(Message);
}
ISDSC_STATUS DiscpUnicodeToAnsiSize(
IN __in PWCHAR UnicodeString,
OUT ULONG *AnsiSizeInBytes
)
/*++
Routine Description:
This routine will return the length needed to represent the unicode
string as ANSI
Arguments:
UnicodeString is the unicode string whose ansi length is returned
*AnsiSizeInBytes is number of bytes needed to represent unicode
string as ANSI
Return Value:
ERROR_SUCCESS or error code
--*/
{
_try
{
*AnsiSizeInBytes = WideCharToMultiByte(CP_ACP,
0,
UnicodeString,
-1,
NULL,
0, NULL, NULL);
} _except(EXCEPTION_EXECUTE_HANDLER) {
return(ERROR_NOACCESS);
}
return((*AnsiSizeInBytes == 0) ? GetLastError() : ERROR_SUCCESS);
}
ULONG DiscpUnicodeToAnsi(
IN __in_opt LPWSTR pszW,
OUT __deref_out LPSTR *ppszA,
IN ULONG MaxLen
)
/*++
Routine Description:
Convert Unicode string into its ansi equivalent
Arguments:
pszW is unicode string to convert
*ppszA on entry has a pointer to buffer to write ansi string or
NULL. If NULL then a buffer is allocated
Return Value:
Error code
--*/
{
ULONG cCharacters;
ULONG Status;
ULONG cbAnsiUsed;
BOOLEAN AllocMemory;
//
// If input is null then just return empty
if (pszW == NULL)
{
*ppszA = NULL;
return(ERROR_SUCCESS);
}
if (*ppszA == NULL)
{
Status = DiscpUnicodeToAnsiSize(pszW, &MaxLen);
if (Status == ERROR_SUCCESS)
{
*ppszA = Alloc(MaxLen);
if (*ppszA == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
AllocMemory = FALSE;
} else {
AllocMemory = TRUE;
}
} else {
AllocMemory = FALSE;
}
} else {
AllocMemory = FALSE;
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS)
{
cCharacters = (ULONG)wcslen(pszW)+1;
// Convert to ANSI.
cbAnsiUsed = WideCharToMultiByte(CP_ACP,
0,
pszW,
cCharacters,
*ppszA,
MaxLen,
NULL,
NULL);
if (0 == cbAnsiUsed)
{
Status = GetLastError();
if (AllocMemory)
{
Free(*ppszA);
}
} else {
Status = ERROR_SUCCESS;
}
}
return(Status);
}
void PrintSecurityFlags(
__in PCHAR Indent,
ISCSI_SECURITY_FLAGS SecurityFlags
)
{
printf("%sSecurity Flags : 0x%I64x\n",
Indent,
SecurityFlags
);
if (SecurityFlags & ISCSI_SECURITY_FLAG_TUNNEL_MODE_PREFERRED)
{
printf("%s Tunnel Mode Preferred\n",
Indent
);
}
if (SecurityFlags & ISCSI_SECURITY_FLAG_TRANSPORT_MODE_PREFERRED)
{
printf("%s Transport Mode Preferred\n",
Indent
);
}
if (SecurityFlags & ISCSI_SECURITY_FLAG_PFS_ENABLED)
{
printf("%s PFS Enabled\n",
Indent
);
}
if (SecurityFlags & ISCSI_SECURITY_FLAG_AGGRESSIVE_MODE_ENABLED)
{
printf("%s Aggressive Mode Enabled\n",
Indent
);
}
if (SecurityFlags & ISCSI_SECURITY_FLAG_IKE_IPSEC_ENABLED)
{
printf("%s IPSEC Enabled\n",
Indent
);
}
if (SecurityFlags & ISCSI_SECURITY_FLAG_VALID)
{
printf("%s Security Flags are Valid\n",
Indent
);
}
}
void PrintTargetMapping(
PISCSI_TARGET_MAPPING Mapping
)
{
ULONG j;
#ifdef UNICODE
printf(" Session Id : %I64x-%I64x\n"
" Target Name : %ws\n"
" Initiator : %ws\n"
" Initiator Scsi Device : %ws\n"
" Initiator Bus : %d\n"
" Initiator Target Id : %d\n",
#else
printf(" Session Id : %I64x-%I64x\n"
" Target Name : %s\n"
" Initiator : %s\n"
" Initiator Scsi Device : %s\n"
" Initiator Bus : %d\n"
" Initiator Target Id : %d\n",
#endif
Mapping->SessionId.AdapterUnique,
Mapping->SessionId.AdapterSpecific,
Mapping->TargetName,
Mapping->InitiatorName,
Mapping->OSDeviceName,
Mapping->OSBusNumber,
Mapping->OSTargetNumber
);
for (j = 0; j < Mapping->LUNCount; j++)
{
printf(" Target LUN: 0x%I64x <--> OS Lun: 0x%x\n",
Mapping->LUNList[j].TargetLUN,
Mapping->LUNList[j].OSLUN);
}
printf("\n");
}
void PrintStringList(
__in PSTR Title,
__in PSTR Spacer,
__in PTSTR Buffer,
ULONG SizeInBytes
)
{
printf("%s\n", Title);
while (*Buffer != 0)
{
#ifdef UNICODE
printf("%s\"%ws\"\n", Spacer, Buffer);
#else
printf("%s\"%s\"\n", Spacer, Buffer);
#endif
if (SizeInBytes > 0)
{
while (*Buffer != 0)
{
Buffer++;
SizeInBytes -= sizeof(TCHAR);
}
if (SizeInBytes > 0)
{
Buffer++;
SizeInBytes -= sizeof(TCHAR);
} else {
printf("StringList error2\n");
break;
}
} else {
printf("StringList error\n");
break;
}
}
}
void PrintBuffer(
__in PSTR Spacer,
__in_ecount(Size) PUCHAR Buffer,
ULONG Size
)
{
ULONG i, n;
while (Size > 0)
{
if (Size >= 0x10)
{
n = 0x10;
} else {
n = Size;
}
printf("%s", Spacer);
for (i = 0; i < 0x10; i++)
{
if (i < n)
{
printf("%02x ", Buffer[i]);
} else {
printf(" ");
}
}
printf(" ");
for (i = 0; i < n; i++)
{
if ((Buffer[i] > 0x20) && (Buffer[i] < 0x7f))
{
printf("%c", Buffer[i]);
} else {
printf(".");
}
}
printf("\n");
Buffer += n;
Size -= n;
}
}
void PrintLoginOptions(
__in CHAR *Header,
PISCSI_LOGIN_OPTIONS LoginOptions
)
{
printf("%sVersion : %d\n", Header, LoginOptions->Version);
printf("%sInformation Specified: 0x%x\n",
Header,
LoginOptions->InformationSpecified);
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_HEADER_DIGEST) == ISCSI_LOGIN_OPTIONS_HEADER_DIGEST)
{
printf("%sHeader Digest : ", Header);
if (LoginOptions->HeaderDigest == ISCSI_DIGEST_TYPE_NONE)
{
printf("None\n");
} else if (LoginOptions->HeaderDigest == ISCSI_DIGEST_TYPE_CRC32C) {
printf("CRC-32C\n");
}
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_DATA_DIGEST) == ISCSI_LOGIN_OPTIONS_DATA_DIGEST)
{
printf("%sData Digest : ", Header);
if (LoginOptions->DataDigest == ISCSI_DIGEST_TYPE_NONE)
{
printf("None\n");
} else if (LoginOptions->DataDigest == ISCSI_DIGEST_TYPE_CRC32C) {
printf("CRC-32C\n");
}
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_MAXIMUM_CONNECTIONS) == ISCSI_LOGIN_OPTIONS_MAXIMUM_CONNECTIONS)
{
printf("%sMaximum Connections : %d\n",
Header,
LoginOptions->MaximumConnections);
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_WAIT) == ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_WAIT)
{
printf("%sDefault Time 2 Wait : %d\n",
Header,
LoginOptions->DefaultTime2Wait);
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_RETAIN) == ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_RETAIN)
{
printf("%sDefault Time 2 Retain: %d\n",
Header,
LoginOptions->DefaultTime2Retain);
}
printf("%sLogin Flags : 0x%x\n",
Header,
LoginOptions->LoginFlags);
if ((LoginOptions->LoginFlags &
ISCSI_LOGIN_FLAG_REQUIRE_IPSEC) == ISCSI_LOGIN_FLAG_REQUIRE_IPSEC)
{
printf("%s Require IPsec\n", Header);
}
if ((LoginOptions->LoginFlags &
ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED) == ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED)
{
printf("%s Multipath Enabled\n", Header);
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_AUTH_TYPE) == ISCSI_LOGIN_OPTIONS_AUTH_TYPE)
{
printf("%sAuthentication Type : ", Header);
if (LoginOptions->AuthType == ISCSI_NO_AUTH_TYPE)
{
printf("None\n");
} else if (LoginOptions->AuthType == ISCSI_CHAP_AUTH_TYPE) {
printf("CHAP\n");
} else if (LoginOptions->AuthType == ISCSI_MUTUAL_CHAP_AUTH_TYPE) {
printf("Mutual CHAP\n");
} else {
printf("Unknown - %d\n", LoginOptions->AuthType);
}
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_USERNAME) == ISCSI_LOGIN_OPTIONS_USERNAME)
{
printf("%sUsername : \n", Header);
PrintBuffer(" ",
LoginOptions->Username,
LoginOptions->UsernameLength);
}
if ((LoginOptions->InformationSpecified &
ISCSI_LOGIN_OPTIONS_PASSWORD) == ISCSI_LOGIN_OPTIONS_PASSWORD)
{
printf("%sPassword : <is established>\n", Header);
}
}
//+-------------------------------------------------------------------------
//
// Function: HexStringToULONGLONG (private)
//
// Synopsis: scan lpsz for a number of hex digits (at most 8); update lpsz
// return value in Value; check for chDelim;
//
// Arguments: [lpsz] - the hex string to convert
// [Value] - the returned value
// [cDigits] - count of digits
//
// Returns: TRUE for success
//
//--------------------------------------------------------------------------
BOOL HexStringToULONGLONG(
__in PTSTR lpsz,
ULONGLONG * RetValue,
int cDigits,
__in TCHAR chDelim
)
{
int Count;
ULONGLONG Value;
Value = 0;
for (Count = 0; (Count < cDigits) && (*lpsz != 0); Count++, lpsz++)
{
if (*lpsz >= TEXT('0') && *lpsz <= TEXT('9'))
Value = (Value << 4) + *lpsz - TEXT('0');
else if (*lpsz >= TEXT('A') && *lpsz <= TEXT('F'))
Value = (Value << 4) + *lpsz - TEXT('A') + 10;
else if (*lpsz >= TEXT('a') && *lpsz <= TEXT('f'))
Value = (Value << 4) + *lpsz - TEXT('a') + 10;
else
return(FALSE);
}
*RetValue = Value;
if (chDelim != 0)
return *lpsz++ == chDelim;
else
return TRUE;
}
BOOLEAN StringToSessionId(
IN __in PTSTR String,
OUT PISCSI_UNIQUE_SESSION_ID SessionId
)
{
PTCHAR s, x;
TCHAR c;
//
// Session id is in the form of
// 0x1234567812345678-0x1234567812345678
//
//
// skip over '0x'
//
if ((*String == TEXT('0')) &&
((String[1] == TEXT('x')) || (String[1] == TEXT('X'))))
{
String += 2;
}
s = String;
while ((*String != TEXT('-') && (String[1] != 0)))
String++;
if (*String == 0)
{
return(FALSE);
}
x = String;
c = *x;
*String++ = 0;
if (! HexStringToULONGLONG(s,
&SessionId->AdapterUnique,
sizeof(ULONGLONG)*2, 0))
{
*x = c;
return(FALSE);
}
*x = c;
if ((*String == TEXT('0')) &&
((String[1] == TEXT('x') ) || (String[1] == TEXT('X'))))
{
String += 2;
}
if (! HexStringToULONGLONG(String,
&SessionId->AdapterSpecific,
sizeof(ULONGLONG)*2, 0))
{
return(FALSE);
}
return(TRUE);
}
ULONG xtoi_(LPCTSTR lpsz)
{
ULONG Count;
ULONG Value;
ULONG cDigits = (ULONG)_tcslen(lpsz);
Value = 0;
for (Count = 0; Count < cDigits; Count++, lpsz++)
{
if (*lpsz >= TEXT('0') && *lpsz <= TEXT('9'))
Value = (Value << 4) + *lpsz - TEXT('0');
else if (*lpsz >= TEXT('A') && *lpsz <= TEXT('F'))
Value = (Value << 4) + *lpsz - TEXT('A') + 10;
else if (*lpsz >= TEXT('a') && *lpsz <= TEXT('f'))
Value = (Value << 4) + *lpsz - TEXT('a') + 10;
else
return(0);
}
return(Value);
}
ISDSC_STATUS ParseHexString(
IN LPCTSTR s,
OUT PUCHAR *BufPtr,
OUT ULONG *BufLen
)
{
ISDSC_STATUS Status;
TCHAR temp[3];
PUCHAR b;
ULONG slen, blen;
ULONG i,j;
slen = (ULONG)_tcslen(s);
blen = slen/2;
if ((blen*2) == slen)
{
*BufLen = blen;
b = Alloc(blen);
if (b != NULL)
{
for (i = 0, j = 0; i < slen; i += 2, j++)
{
temp[0] = s[i];
temp[1] = s[i+1];
temp[2] = 0;
b[j] = (UCHAR)xtoi_(temp);
}
*BufPtr = b;
Status = ERROR_SUCCESS;
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
//
// string must have 2 characters for each binary value
//
Status = ERROR_INVALID_PARAMETER;
}
return(Status);
}
ULONG stoi(
__in PTCHAR x
)
{
ULONG r;
if ((_tcslen(x) > 2) &&
(x[0] == TEXT('0')) &&
((x[1] == TEXT('x')) || (x[1] == TEXT('X'))))
{
r = xtoi_(x+2);
} else {
#ifdef UNICODE
r = _wtoi(x);
#else
r = atoi(x);
#endif
}
return(r);
}
ULONGLONG stoiD(
__in PTCHAR x
)
{
ULONGLONG r;
ULONG base;
if ((_tcslen(x) > 2) &&
(x[0] == TEXT('0')) &&
((x[1] == TEXT('x')) || (x[1] == TEXT('X'))))
{
base = 16;
x += 2;
} else {
base = 10;
}
r = _tcstoui64(x,
NULL,
base);
return(r);
}
BOOLEAN stoiDForLogicalUnit(
__in PTCHAR x,
ULONGLONG *Value
)
{
if ((_tcslen(x) != 18) ||
(x[0] != TEXT('0')) ||
((x[1] != TEXT('x')) && (x[1] == TEXT('X'))))
{
return(FALSE);
}
*Value = stoiD(x);
return(TRUE);
}
void ParseLoginOptions(
PISCSI_LOGIN_OPTIONS LoginOptions,
__in_ecount(ArgC) PTSTR *ArgV,
ULONG ArgC,
ULONG ArgCIndex
)
{
ISDSC_STATUS Status;
PTCHAR Secret;
UNREFERENCED_PARAMETER(ArgC);
memset(LoginOptions, 0, sizeof(ISCSI_LOGIN_OPTIONS));
LoginOptions->InformationSpecified = 0;
LoginOptions->LoginFlags = 0;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->LoginFlags = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_HEADER_DIGEST;
LoginOptions->HeaderDigest = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_DATA_DIGEST;
LoginOptions->DataDigest = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_MAXIMUM_CONNECTIONS;
LoginOptions->MaximumConnections = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_WAIT;
LoginOptions->DefaultTime2Wait = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_DEFAULT_TIME_2_RETAIN;
LoginOptions->DefaultTime2Retain = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_USERNAME;
if (*ArgV[ArgCIndex] == TEXT('-'))
{
LoginOptions->Username = NULL;
LoginOptions->UsernameLength = 0;
} else {
#ifdef UNICODE
LoginOptions->Username = NULL;
DiscpUnicodeToAnsi(
ArgV[ArgCIndex],
(LPSTR *)&LoginOptions->Username,
0);
#else
LoginOptions->Username = ArgV[ArgCIndex];
#endif
LoginOptions->UsernameLength = (ULONG)strlen((LPCSTR)LoginOptions->Username);
}
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_PASSWORD;
if (*ArgV[ArgCIndex] == TEXT('-'))
{
LoginOptions->Password = NULL;
LoginOptions->PasswordLength = 0;
} else {
Secret = ArgV[ArgCIndex];
if ((Secret[0] == TEXT('0')) &&
((Secret[1] == TEXT('X')) ||
(Secret[1] == TEXT('x'))))
{
Status = ParseHexString(Secret+2,
&LoginOptions->Password,
&LoginOptions->PasswordLength);
} else {
#ifdef UNICODE
LoginOptions->Password = NULL;
DiscpUnicodeToAnsi(
ArgV[ArgCIndex],
(LPSTR *)&LoginOptions->Password,
0);
#else
LoginOptions->Password = ArgV[ArgCIndex];
#endif
LoginOptions->PasswordLength = (ULONG)strlen((LPCSTR)LoginOptions->Password);
}
}
}
ArgCIndex++;
if (*ArgV[ArgCIndex] != TEXT('*'))
{
LoginOptions->InformationSpecified |= ISCSI_LOGIN_OPTIONS_AUTH_TYPE;
LoginOptions->AuthType = stoi(ArgV[ArgCIndex]);
}
ArgCIndex++;
}
BOOLEAN IsTrue(
__in PTCHAR s,
BOOLEAN Default
)
{
if (*s == TEXT('*'))
{
return(Default);
}
if ( (*s == TEXT('t')) || (*s == TEXT('T')))
{
return(TRUE);
}
return(FALSE);
}
ISDSC_STATUS TunnelAddress(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli TunnelAddr <Initiator Name> <InitiatorPort> <Destination
// Address> <Tunnel Address> <Persist>
{
ISDSC_STATUS Status;
PTCHAR Initiator, DestAddress, TunnelAddress;
BOOLEAN Persist;
ULONG InitiatorPort;
if (ArgC != 7)
{
Usage(28);
return(ERROR_SUCCESS);
}
Initiator = ArgV[2];
if (*Initiator == TEXT('*'))
{
Initiator = NULL;
}
if (*ArgV[3] == TEXT('*'))
{
InitiatorPort = ISCSI_ALL_INITIATOR_PORTS;
} else {
InitiatorPort = stoi(ArgV[3]);
}
DestAddress = ArgV[4];
if (*DestAddress == TEXT('*'))
{
DestAddress = NULL;
}
TunnelAddress = ArgV[5];
if (*TunnelAddress == TEXT('*'))
{
TunnelAddress = NULL;
}
Persist = IsTrue(ArgV[6], TRUE);
Status = SetIScsiTunnelModeOuterAddress(Initiator,
InitiatorPort,
DestAddress,
TunnelAddress,
Persist);
return(Status);
}
ISDSC_STATUS GroupKey(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli GroupKey <Key> <Persist>
{
ISDSC_STATUS Status;
PCHAR Key;
ULONG KeyLength = 0;
BOOLEAN Persist;
if (ArgC != 4)
{
Usage(29);
return(ERROR_SUCCESS);
}
if (*ArgV[2] == TEXT('*'))
{
Key = NULL;
KeyLength = 0;
Status = ERROR_SUCCESS;
} else {
#ifdef UNICODE
Key = NULL;
Status = DiscpUnicodeToAnsi(ArgV[2],
&Key,
0);
#else
Key = ArgV[2];
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
KeyLength = (ULONG)strlen(Key) + 1;
}
}
if (Status == ERROR_SUCCESS)
{
Persist = IsTrue(ArgV[3], TRUE);
Status = SetIScsiGroupPresharedKey(KeyLength,
(PUCHAR)Key,
Persist);
#ifdef UNICODE
if (Key != NULL)
{
Free(Key);
}
#endif
}
return(Status);
}
ISDSC_STATUS CHAPSecret(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli CHAPSecret <secret>
{
ISDSC_STATUS Status = ERROR_SUCCESS;
PUCHAR Key;
ULONG KeyLength = 0;
PTCHAR Secret;
if (ArgC != 3)
{
Usage(27);
return(Status);
}
Secret = ArgV[2];
if (*Secret == TEXT('*'))
{
Key = NULL;
KeyLength = 0;
} else {
if ((Secret[0] == TEXT('0')) &&
((Secret[1] == TEXT('X')) ||
(Secret[1] == TEXT('x'))))
{
Status = ParseHexString(Secret+2,
&Key,
&KeyLength);
} else {
#ifdef UNICODE
Key = NULL;
Status = DiscpUnicodeToAnsi(ArgV[2],
(LPSTR *)&Key,
0);
#else
Key = ArgV[2];
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
KeyLength = (ULONG)strlen((LPCSTR)Key);
}
}
}
if (Status == ERROR_SUCCESS)
{
Status = SetIScsiInitiatorCHAPSharedSecret(KeyLength,
Key);
if ((Key != NULL) && (Key != (PUCHAR)ArgV[2]))
{
Free(Key);
}
}
return(Status);
}
ISDSC_STATUS BindPeristentVolumes(
int ArgC ,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli BindPersistentVolumes\n");
{
ISDSC_STATUS Status;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
Status = SetupPersistentIScsiVolumes();
return(Status);
}
ISDSC_STATUS ClearPersistentVolumes(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli ClearPersistentVolumes\n");
{
ISDSC_STATUS Status;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
Status = ClearPersistentIScsiDevices();
return(Status);
}
ISDSC_STATUS AddPersistentVolume(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli AddPersistentVolume <Volume Path>\n");
{
ISDSC_STATUS Status;
if (ArgC != 3)
{
Usage(38);
Status = ERROR_SUCCESS;
} else {
Status = AddPersistentIScsiDevice(ArgV[2]);
}
return(Status);
}
ISDSC_STATUS RemovePersistentVolume(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli RemovePersistentVolume <Volume Path>\n");
{
ISDSC_STATUS Status;
if (ArgC != 3)
{
Usage(39);
Status = ERROR_SUCCESS;
} else {
Status = RemovePersistentIScsiDevice(ArgV[2]);
}
return(Status);
}
ISDSC_STATUS ReportPersistentVolumes(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli ReportPersistentVolumes\n");
{
ISDSC_STATUS Status;
ULONG SizeNeeded;
PTCHAR Buffer;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
SizeNeeded = 0;
Status = ReportPersistentIScsiDevices(&SizeNeeded,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Buffer = Alloc(SizeNeeded * sizeof(TCHAR));
if (Buffer != NULL)
{
Status = ReportPersistentIScsiDevices(&SizeNeeded,
Buffer);
if (Status == ERROR_SUCCESS)
{
PrintStringList("Persistent Volumes",
"",
Buffer,
SizeNeeded);
printf("\n");
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
}
return(Status);
}
ISDSC_STATUS NodeName(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli NodeName <node name>
{
ISDSC_STATUS Status;
PTCHAR NodeName;
if (ArgC != 3)
{
Usage(25);
return(ERROR_SUCCESS);
}
if (*ArgV[2] == TEXT('*'))
{
NodeName = NULL;
} else {
NodeName = ArgV[2];
}
Status = SetIScsiInitiatorNodeName(NodeName);
return(Status);
}
BOOLEAN DiscpIsDeviceNumberInVolume(
IN ULONG DeviceNumber,
IN PVOLUME_DISK_EXTENTS Volume
)
/*
Description:
This routine will determine if the disk represented by a disk
device number is part of a volume
Arguments:
DeviceNumber is the disk device number
Volume is the VOLUME_DISK_EXTENTS for the volume
Return Values:
Status
*/
{
ULONG i;
for (i = 0; i < Volume->NumberOfDiskExtents; i++)
{
if (Volume->Extents[i].DiskNumber == DeviceNumber)
{
return(TRUE);
}
}
return(FALSE);
}
PTCHAR DiscpIsStringInList(
IN PTCHAR List,
IN PTCHAR String
)
/*
Description:
This routine will determine if a string is already in a list of
REG_MULTI_SZ. If so a pointer to where the string is located is
returned.
Arguments:
List has a pointer to a REG_MULTI_SZ list
String is the string to find in the list
Return Values:
Pointer to the string in the list or NULL if string is not in the
list
*/
{
PTCHAR p;
p = List;
if (*p == 0)
{
//
// Empty list
//
return(NULL);
}
do
{
if (_tcsicmp(p, String) == 0)
{
//
// We found our string in the list
//
return(p);
}
//
// Advance to next string
//
p += (_tcslen(p) + 1);
} while (*p != 0);
return(NULL);
}
ISDSC_STATUS DiscpAddStringToMultiSzList(
IN OUT PTCHAR *List,
IN OUT PULONG ListSizeInBytes,
IN PTCHAR String
)
/*
Description:
This routine will add a string to the end of a REG_MULTI_SZ list.
It will reallocate the list buffer and copy over the existing
contents and add the new string to the end of the list. If the
string is already in the list then the string is not added
Arguments:
*List on entry has a pointer to the REG_MULTI_SZ list. The memory
used by the list should be allocated via DiscpAllocMemory. On
return it has a pointer to the newly allocated buffer or NULL.
*ListSizeInBytes on entry has the number of bytes contained in the
REG_MULTI_SZ buffer. On return it is updated with the new
number of bytes in the buffer.
String is the string to add to the end of the buffer
Return Values:
Status
*/
{
ISDSC_STATUS Status;
size_t NewListSizeInBytes;
PTCHAR NewList;
PTCHAR p;
ULONG Len;
HRESULT hr;
//
// First see if the string is already in the list
//
if ((DiscpIsStringInList(*List,
String)) == NULL)
{
if (*ListSizeInBytes != sizeof(TCHAR))
{
NewListSizeInBytes = *ListSizeInBytes +
((_tcslen(String)+1) * sizeof(TCHAR));
} else {
NewListSizeInBytes = ((_tcslen(String)+2) * sizeof(TCHAR));
}
NewList = Alloc(NewListSizeInBytes);
if (NewList != NULL)
{
if (*ListSizeInBytes != sizeof(TCHAR))
{
//
// Copy over existing list except for second nul terminator
// at end
//
Len = (*ListSizeInBytes) - sizeof(TCHAR);
memcpy(NewList, *List, Len);
} else {
Len = 0;
}
//
// Now copy new string to the end of the list and add the
// extra nul terminator
//
p = (PTCHAR)OffsetToPtr(NewList, Len);
hr = StringCchCopy(p,
(NewListSizeInBytes - Len) / sizeof(WCHAR),
String);
p += (_tcslen(String) + 1);
*p = 0;
//
// return new list pointer and length
//
Free(*List);
*List = NewList;
*ListSizeInBytes = (ULONG)NewListSizeInBytes;
Status = ERROR_SUCCESS;
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
//
// String already in the list, nothing to do
//
Status = ERROR_SUCCESS;
}
return(Status);
}
ISDSC_STATUS DiscpVolumeMountList(
IN PTCHAR Name,
IN PTCHAR VolumeNameToFind,
IN OUT PTCHAR *VolumePath,
IN OUT ULONG *VolumePathLen
)
/*++
Routine Description:
This routine will see if the volume passed or any volumes mounted
on the volume passed are the volume that we are looking for and if
so then add the path to the volume to the list
Arguments:
Name is the volume name for the volume on which to look for volume
paths that are for VolumeNameToFind
VolumeNameToFind is the name of the volume we are searching for
*VolumePath returns with a pointer to the list of volume paths.
Each path in the list is nul terminated with the last path
double nul terminated. The caller must free this buffer.
*VolumePathLen returns with the number of bytes in the
VolumePath buffer
Return Value:
Status
--*/
{
ISDSC_STATUS Status;
PTCHAR VolumeName;
BOOL b;
TCHAR c1, c2;
PTCHAR LinkName1, LinkName2;
PTCHAR VolumeMountPoint;
PTCHAR MountPointPath;
HANDLE h;
HRESULT hr;
VolumeName = Alloc(5 * (MAX_PATH * sizeof(TCHAR)));
if (VolumeName != NULL)
{
Status = ERROR_SUCCESS;
LinkName1 = (PTCHAR)OffsetToPtr(VolumeName,
MAX_PATH * sizeof(TCHAR));
LinkName2 = (PTCHAR)OffsetToPtr(LinkName1,
MAX_PATH * sizeof(TCHAR));
VolumeMountPoint = (PTCHAR)OffsetToPtr(LinkName2,
MAX_PATH * sizeof(TCHAR));
MountPointPath = (PTCHAR)OffsetToPtr(VolumeMountPoint,
MAX_PATH * sizeof(TCHAR));
//
// See if the mount point is for our volume name
//
b = GetVolumeNameForVolumeMountPoint(Name,
VolumeName,
MAX_PATH);
if (b)
{
if (_tcsicmp(VolumeName,
VolumeNameToFind) == 0)
{
//
// we found a mountpoint for our volume name,
// lets add it to the list
//
Status = DiscpAddStringToMultiSzList(VolumePath,
VolumePathLen,
Name);
} else {
c1 = VolumeName[48];
c2 = VolumeNameToFind[48];
VolumeName[48] = 0;
VolumeNameToFind[48] = 0;
if (QueryDosDevice(&VolumeName[4],
LinkName1,
MAX_PATH) &&
QueryDosDevice(&VolumeNameToFind[4],
LinkName2,
MAX_PATH))
{
if (_tcscmp(LinkName1, LinkName2) == 0)
{
Status = DiscpAddStringToMultiSzList(VolumePath,
VolumePathLen,
Name);
}
}
VolumeName[48] = c1;
VolumeNameToFind[48] = c2;
}
h = FindFirstVolumeMountPoint(VolumeName,
VolumeMountPoint,
MAX_PATH);
if (h != INVALID_HANDLE_VALUE)
{
do
{
hr = StringCchCopy(MountPointPath,
MAX_PATH,
Name);
hr = StringCchCat(MountPointPath,
MAX_PATH,
VolumeMountPoint);
Status = DiscpVolumeMountList(MountPointPath,
VolumeNameToFind,
VolumePath,
VolumePathLen);
b = FindNextVolumeMountPoint(h,
VolumeMountPoint,
MAX_PATH);
} while ((Status == ERROR_SUCCESS) && b);
FindVolumeMountPointClose(h);
}
}
Free(VolumeName);
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return(Status);
}
ISDSC_STATUS DiscpGetVolumePathNamesForVolumeName(
IN PTCHAR VolumeNameToFind,
OUT PTCHAR *VolumePath,
OUT ULONG *VolumePathLen
)
/*++
Routine Description:
My implementation of the GetVolumePathNamesForVolumeName
functionality, but for W2K. What we need to do is to find the
volume name for every drive letter and then the volume name for
every mount point and if any of them match our volume name then
we've got a mapping. Note there could be multiple paths for a
volume name.
Arguments:
VolumeNameToFind is the name of the volume
*VolumePath returns with a pointer to the list of volume paths.
Each path in the list is nul terminated with the last path
double nul terminated. The caller must free this buffer.
*VolumePathLen returns with the number of characters in the
VolumePath buffer
Return Value:
Status
--*/
{
ISDSC_STATUS Status;
TCHAR c;
TCHAR Drive[4];
//
// Initialize output volume path list to double nul
//
*VolumePathLen = sizeof(TCHAR);
*VolumePath = (PTCHAR)Alloc(*VolumePathLen);
if (*VolumePath != NULL)
{
(*VolumePath)[0] = 0;
//
// Loop through all drive letters looking for mount points that
// match our volume name
//
Drive[1] = L':';
Drive[2] = L'\\';
Drive[3] = 0;
for (c = L'C', Status = ERROR_SUCCESS;
((c < (L'Z' + 1)) && (Status == ERROR_SUCCESS));
c++)
{
Drive[0] = c;
Status = DiscpVolumeMountList(Drive,
VolumeNameToFind,
VolumePath,
VolumePathLen);
}
//
// COnvet VolumePathLen from bytes to characters
//
*VolumePathLen = *VolumePathLen / sizeof(TCHAR);
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return(Status);
}
typedef BOOL (*GETVOLUMEPATHNAMESFORVOLUMENAMEAPI)(
LPCTSTR lpszVolumeName,
LPTSTR lpszVolumePathNames,
DWORD cchBufferLength,
PDWORD lpcchReturnLength
);
ISDSC_STATUS DiscpVolumeNameToVolumePath(
IN PTCHAR VolumeName,
OUT PTCHAR *VolumePath,
OUT ULONG *VolumePathLen
)
/*++
Routine Description:
This routine will map a volume name to the volume paths for it. XP
and W2003 have a nifty function that does this easily, but it is
not available on W2K. So this routine will figure out if we are on
W2K or not and do it the hard way on W2K or the easy way on XP and
W2003. This api should behave in a functionally identical way to
the GetVolumePathNamesForVolumeName api.
Arguments:
VolumeName is the name of the volume
*VolumePath returns with a pointer to the list of volume paths.
Each path in the list is nul terminated with the last path
double nul terminated. The caller must free this buffer.
*VolumePathLen returns with the number of characters in the
VolumePath buffer
Return Value:
Status
--*/
{
ISDSC_STATUS Status;
OSVERSIONINFOEX VersionInfo;
BOOL b;
HMODULE Module;
GETVOLUMEPATHNAMESFORVOLUMENAMEAPI GetVolumePathNamesForVolumeNameApi;
PTCHAR p;
ULONG CharNeeded;
VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (GetVersionEx((LPOSVERSIONINFO)&VersionInfo))
{
if ((VersionInfo.dwMajorVersion == 5) &&
(VersionInfo.dwMinorVersion == 0))
{
//
// We are on W2K so we need to do the mapping from volume
// name to VolumePath the hard way
//
Status = DiscpGetVolumePathNamesForVolumeName(VolumeName,
VolumePath,
VolumePathLen);
} else {
//
// Since we are on XP or W2003 then we can use the
// advanced API so load it up from kernel32.dll
//
Module = GetModuleHandle(TEXT("Kernel32.Dll"));
GetVolumePathNamesForVolumeNameApi =
(GETVOLUMEPATHNAMESFORVOLUMENAMEAPI)GetProcAddress(Module,
"GetVolumePathNamesForVolumeNameW");
if (GetVolumePathNamesForVolumeNameApi != NULL)
{
b = (*GetVolumePathNamesForVolumeNameApi)(VolumeName,
NULL,
0,
&CharNeeded);
Status = b ? ERROR_SUCCESS : GetLastError();
if (Status == ERROR_MORE_DATA)
{
p = Alloc(CharNeeded * sizeof(TCHAR));
if (p != NULL)
{
b = (*GetVolumePathNamesForVolumeNameApi)(VolumeName,
p,
CharNeeded,
&CharNeeded);
Status = b ? ERROR_SUCCESS : GetLastError();
if (Status == ERROR_SUCCESS)
{
*VolumePath = p;
*VolumePathLen = CharNeeded;
} else {
Free(p);
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
} else if (Status == ERROR_SUCCESS) {
p = Alloc(2 * sizeof(TCHAR));
if (p != NULL)
{
p[0] = 0;
p[1] = 0;
*VolumePath = p;
*VolumePathLen = 2;
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
Status = GetLastError();
}
} else {
Status = GetLastError();
}
}
} else {
Status = GetLastError();
}
return(Status);
}
ISDSC_STATUS DiscpEnumerateDeviceInterfaces(
IN LPGUID Guid,
IN ENUMDEVICEINTERFACECALLBACK Callback,
IN PVOID Context,
OUT ULONG *CountPtr,
OUT PDEVICEINTERFACEENTRY *ListPtr
)
{
ISDSC_STATUS Status;
HDEVINFO DevInfo;
BOOL b;
ULONG i, Count;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PDEVICEINTERFACEENTRY List, e;
ULONG DeviceInterfaceDetailDataSize;
//
// get info on all exsiting disk devices
//
DevInfo = SetupDiGetClassDevs(
Guid,
NULL, // IN PCTSTR Enumerator, OPTIONAL
NULL, // IN HWND hwndParent, OPTIONAL
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (DevInfo != INVALID_HANDLE_VALUE)
{
//
// First step is to get the count of disks so we can build our
// list
//
Count = 0;
do
{
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
b = SetupDiEnumDeviceInterfaces(
DevInfo,
NULL, // IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
Guid,
Count,
&DeviceInterfaceData
);
Count++;
} while (b);
Status = GetLastError();
if (Status == ERROR_NO_MORE_ITEMS)
{
Count--;
//
// Now that we've got a rough count, lets loop over all of the
// disks again and build up out data structs
//
*CountPtr = 0;
if (Count > 0)
{
//
// Allocate space for all of the entries
//
List = Alloc(Count * sizeof(DEVICEINTERFACEENTRY));
if (List != NULL)
{
*ListPtr = List;
memset(List, 0, Count * sizeof(DEVICEINTERFACEENTRY));
i = 0;
while (i < Count)
{
//
// Call setupdi to get the information needed for
// each interface
//
e = &List[(*CountPtr)];
e->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
b = SetupDiEnumDeviceInterfaces(
DevInfo,
NULL, // IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
Guid,
i++,
&e->DeviceInterfaceData
);
if (b)
{
DeviceInterfaceDetailDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
(MAX_PATH * sizeof(TCHAR));
e->DeviceInterfaceDetailData = Alloc(DeviceInterfaceDetailDataSize);
if (e->DeviceInterfaceDetailData != NULL)
{
e->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
e->DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
b = SetupDiGetDeviceInterfaceDetail(
DevInfo,
&e->DeviceInterfaceData,
e->DeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize,
&DeviceInterfaceDetailDataSize,
&e->DeviceInfoData);
if ((b == FALSE) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
//
// If buffer was too small for
// DeviceInterfaceDetailData then try
// the call again
//
Free(e->DeviceInterfaceDetailData);
e->DeviceInterfaceDetailData = Alloc(DeviceInterfaceDetailDataSize);
if (e->DeviceInterfaceDetailData != NULL)
{
e->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
e->DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
b = SetupDiGetDeviceInterfaceDetail(
DevInfo,
&e->DeviceInterfaceData,
e->DeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize,
&DeviceInterfaceDetailDataSize,
&e->DeviceInfoData);
}
}
if (b)
{
//
// if we've successfully gathered all
// of our info, then we do the callout
// for the specific work
//
if (Callback != NULL)
{
Status = (*Callback)(Context,
Guid,
DevInfo,
e);
} else {
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS)
{
(*CountPtr)++;
} else {
Free(e->DeviceInterfaceDetailData);
}
} else {
if (e->DeviceInterfaceDetailData != NULL)
{
Free(e->DeviceInterfaceDetailData);
}
}
}
}
}
Status = ERROR_SUCCESS;
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
SetupDiDestroyDeviceInfoList(DevInfo);
} else {
Status = GetLastError();
}
return(Status);
}
void DiscpFreeDeviceInterfaceList(
IN ULONG Count,
IN PDEVICEINTERFACEENTRY List
)
/*++
Description:
This routine will free all of the memory allocate for a device
interface list
Arguments:
Count is the number of entries in the list
List is the list of device entries
Return Values:
ERROR_SUCCESS or error code
--*/
{
ULONG i;
for (i = 0; i < Count; i++)
{
Free(List[i].DeviceInterfaceDetailData);
if (List[i].MoreInfo != NULL)
{
Free(List[i].MoreInfo);
}
}
Free(List);
}
ISDSC_STATUS DiscpVolumeDeviceInterfaceCallback(
IN PVOID Context,
IN LPGUID Guid,
IN HDEVINFO DevInfo,
IN OUT PDEVICEINTERFACEENTRY DevEntry
)
/*++
Routine Description:
This routine is the volume device interface callback. It gets
additional information about each volume that is found. Information
includes the disk extents and the volume path names.
Arguments:
Context is not used
Guid is the guid for the volume device interface
DevInfo is the DevInfo set for the enumeration
DevEntry is the device interface information structure. This
routine will insert a pointer to the VOLUME_DISK_EXTENTS for
the device interface
Return Value:
Status
--*/
{
HANDLE Handle;
ULONG Status;
BOOL b;
ULONG Returned;
ULONG ExtentSize = sizeof(VOLUME_DISK_EXTENTS) + 1024 * sizeof(DISK_EXTENT);
ULONG VolumeSize, Size;
PVOLUMEMOREINFO VolumeMoreInfo;
PTCHAR VolumeName, VolumeMP;
PTCHAR VolumePath;
size_t VolumeMPLen;
HRESULT hr;
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(Guid);
UNREFERENCED_PARAMETER(DevInfo);
VolumeMPLen = _tcslen(DevEntry->DeviceInterfaceDetailData->DevicePath) +2;
VolumeName = Alloc((VolumeMPLen + MAX_PATH) *
sizeof(TCHAR));
if (VolumeName != NULL)
{
//
// Append a \ to the end of the device interface name because that
// is what GetVolumeNameForVolumeMountPoint wants
//
VolumeMP = (PTCHAR)OffsetToPtr(VolumeName, MAX_PATH * sizeof(TCHAR));
hr = StringCchCopy(VolumeMP,
VolumeMPLen,
DevEntry->DeviceInterfaceDetailData->DevicePath);
hr = StringCchCat(VolumeMP,
VolumeMPLen,
TEXT("\\"));
b = GetVolumeNameForVolumeMountPoint(VolumeMP,
VolumeName,
MAX_PATH);
if (b)
{
//
// Now we have the volume name, we can get the volume paths
// that can access it. First figure out the size needed for
// the pathname buffer
//
Status = DiscpVolumeNameToVolumePath(VolumeName,
&VolumePath,
&VolumeSize);
if (Status == ERROR_SUCCESS)
{
//
// Get the disk extents for the volume
//
Size = ExtentSize + (VolumeSize * sizeof(TCHAR));
Handle = CreateFile(DevEntry->DeviceInterfaceDetailData->DevicePath,
GENERIC_READ, // access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL);
if (Handle != INVALID_HANDLE_VALUE)
{
DevEntry->MoreInfo = Alloc(Size);
if (DevEntry->MoreInfo != NULL)
{
VolumeMoreInfo = (PVOLUMEMOREINFO)DevEntry->MoreInfo;
b = DeviceIoControl(
Handle,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, // operation
NULL, // input data buffer
0, // size of input data buffer
VolumeMoreInfo->VolumeDiskExtentsBuffer, // output data buffer
ExtentSize, // size of output data buffer
&Returned, // byte count
NULL // overlapped information
);
if (b)
{
//
// And if all goes well, get the volume
// path names for the volume
//
memcpy(VolumeMoreInfo->VolumePathNames,
VolumePath,
VolumeSize * sizeof(TCHAR));
Status = ERROR_SUCCESS;
} else {
Free(DevEntry->MoreInfo);
DevEntry->MoreInfo = NULL;
Status = GetLastError();
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
CloseHandle(Handle);
} else {
Status = GetLastError();
}
Free(VolumePath);
}
} else {
Status = GetLastError();
}
Free(VolumeName);
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return(Status);
}
PCHAR DeviceTypeFromGuid(
LPGUID Guid
)
{
if (memcmp(Guid,
&GUID_DEVINTERFACE_DISK,
sizeof(GUID)) == 0)
{
return("Disk");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_TAPE,
sizeof(GUID)) == 0)
{
return("Tape");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_CDROM,
sizeof(GUID)) == 0)
{
return("CDRom");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_WRITEONCEDISK,
sizeof(GUID)) == 0)
{
return("Write Once Disk");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_CDCHANGER,
sizeof(GUID)) == 0)
{
return("CD Changer");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_MEDIUMCHANGER,
sizeof(GUID)) == 0)
{
return("Medium Changer");
}
if (memcmp(Guid,
&GUID_DEVINTERFACE_FLOPPY,
sizeof(GUID)) == 0)
{
return("Floppy");
}
return("Unknown");
}
ISDSC_STATUS GetMountPointsFromDeviceNumber(
IN ULONG DeviceNumber,
IN ULONG VolumeCount,
IN PDEVICEINTERFACEENTRY VolumeList,
IN OUT ULONG *VolumeIndex
)
/*
Description:
This routine will return the index of the volume that the device
belongs.
Arguments:
DeviceNumber has the disk device number
VolumeCount has the number of volumes
VolumeList has information about the voluem device interfaces
*VoluemIndex on entry has the next index in the list to being the
search. On return it has the index into volume list for the
next match.
Return Values:
Status
*/
{
ULONG j;
ISDSC_STATUS Status = ERROR_INVALID_PARAMETER;
PVOLUMEMOREINFO VolumeMoreInfo;
for (j = *VolumeIndex; j < VolumeCount; j++)
{
if (VolumeList[j].MoreInfo != NULL)
{
VolumeMoreInfo = (PVOLUMEMOREINFO)VolumeList[j].MoreInfo;
if (DiscpIsDeviceNumberInVolume(DeviceNumber,
&VolumeMoreInfo->VolumeDiskExtents))
{
*VolumeIndex = j;
Status = ERROR_SUCCESS;
break;
}
}
}
return(Status);
}
ISDSC_STATUS SessionList(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli SessionList
{
ISDSC_STATUS Status;
PISCSI_SESSION_INFO SessionInfo;
PISCSI_CONNECTION_INFO ConnectionInfo;
ULONG i,j;
ULONG SessionCount, SizeNeeded;
BOOLEAN ShowDeviceInfo = TRUE;
ISDSC_STATUS StatusDontCare;
BOOLEAN HeaderPrinted;
if ((ArgC < 2) || (ArgC > 3))
{
Usage(26);
return(ERROR_SUCCESS);
}
if (ArgC == 3)
{
ShowDeviceInfo = IsTrue(ArgV[2],
TRUE);
}
SizeNeeded = 0;
Status = GetIScsiSessionList(
&SizeNeeded,
&SessionCount,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
SessionInfo = (PISCSI_SESSION_INFO)Alloc(SizeNeeded);
if (SessionInfo == NULL)
{
printf("Couldn't alloc for session list\n");
return(ERROR_NOT_ENOUGH_MEMORY);
}
Status = GetIScsiSessionList(
&SizeNeeded,
&SessionCount,
SessionInfo);
} else {
SessionCount = 0;
SessionInfo = NULL;
}
if (Status == ERROR_SUCCESS)
{
printf("Total of %d sessions\n\n", SessionCount);
for (i = 0; i < SessionCount; i++, SessionInfo++)
{
#if UNICODE
printf("Session Id : %I64x-%I64x\n"
"Initiator Node Name : %ws\n"
"Target Node Name : %ws\n"
"Target Name : %ws\n"
"ISID : %02x %02x %02x %02x %02x %02x\n"
"TSID : %02x %02x\n"
"Number Connections : %d\n",
SessionInfo->SessionId.AdapterUnique,
SessionInfo->SessionId.AdapterSpecific,
SessionInfo->InitiatorName,
SessionInfo->TargetNodeName,
SessionInfo->TargetName,
SessionInfo->ISID[0],
SessionInfo->ISID[1],
SessionInfo->ISID[2],
SessionInfo->ISID[3],
SessionInfo->ISID[4],
SessionInfo->ISID[5],
SessionInfo->TSID[0],
SessionInfo->TSID[1],
SessionInfo->ConnectionCount);
#else
printf("Session Id : %I64x-%I64x\n"
"Initiator Node Name : %s\n"
"Target Node Name : %s\n"
"Target Name : %s\n"
"ISID : %02x %02x %02x %02x %02x %02x\n"
"TSID : %02x %02x\n"
"Number Connections : %d\n",
SessionInfo->SessionId.AdapterUnique,
SessionInfo->SessionId.AdapterSpecific,
SessionInfo->InitiatorName,
SessionInfo->TargetNodeName,
SessionInfo->TargetName,
SessionInfo->ISID[0],
SessionInfo->ISID[1],
SessionInfo->ISID[2],
SessionInfo->ISID[3],
SessionInfo->ISID[4],
SessionInfo->ISID[5],
SessionInfo->TSID[0],
SessionInfo->TSID[1],
SessionInfo->ConnectionCount);
#endif
if (SessionInfo->ConnectionCount > 0)
{
printf("\n Connections:\n");
}
for (j = 0; j < SessionInfo->ConnectionCount; j++)
{
ConnectionInfo = &SessionInfo->Connections[j];
#ifdef UNICODE
printf(" Connection Id : %I64x-%I64x\n"
" Initiator Portal : %ws/%d\n"
" Target Portal : %ws/%d\n"
" CID : %02x %02x\n",
ConnectionInfo->ConnectionId.AdapterUnique,
ConnectionInfo->ConnectionId.AdapterSpecific,
ConnectionInfo->InitiatorAddress,
ConnectionInfo->InitiatorSocket,
ConnectionInfo->TargetAddress,
ConnectionInfo->TargetSocket,
ConnectionInfo->CID[0],
ConnectionInfo->CID[1]);
#else
printf(" Connection Id : %I64x-%I64x\n"
" Initiator Portal : %s/%d\n"
" Target Portal : %s/%d\n"
" CID : %02x %02x\n",
ConnectionInfo->ConnectionId.AdapterUnique,
ConnectionInfo->ConnectionId.AdapterSpecific,
ConnectionInfo->InitiatorAddress,
ConnectionInfo->InitiatorSocket,
ConnectionInfo->TargetAddress,
ConnectionInfo->TargetSocket,
ConnectionInfo->CID[0],
ConnectionInfo->CID[1]);
#endif
}
printf("\n");
if (ShowDeviceInfo)
{
ULONG DeviceCount;
PISCSI_DEVICE_ON_SESSION DeviceList;
ULONG VolumeCount;
PDEVICEINTERFACEENTRY VolumeList;
ULONG k;
PTCHAR p;
PVOLUMEMOREINFO VolumeMoreInfo;
ULONG VolumeIndex;
Status = GetDevicesForIScsiSession(&SessionInfo->SessionId,
&DeviceCount,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
DeviceList = Alloc(DeviceCount *
sizeof(ISCSI_DEVICE_ON_SESSION));
if (DeviceList != NULL)
{
Status = GetDevicesForIScsiSession(&SessionInfo->SessionId,
&DeviceCount,
DeviceList);
if ((Status == ERROR_SUCCESS) &&
(DeviceCount > 0))
{
Status = DiscpEnumerateDeviceInterfaces((LPGUID)&GUID_DEVINTERFACE_VOLUME,
DiscpVolumeDeviceInterfaceCallback,
NULL,
&VolumeCount,
&VolumeList);
if (Status != ERROR_SUCCESS)
{
VolumeCount = 0;
VolumeList = NULL;
}
printf(" Devices:\n");
for (k = 0; k < DeviceCount; k++)
{
printf(" Device Type : %s\n",
DeviceTypeFromGuid(&DeviceList[k].DeviceInterfaceType));
printf(" Device Number : %d\n",
DeviceList[k].StorageDeviceNumber.DeviceNumber);
printf(" Storage Device Type : %d\n",
DeviceList[k].StorageDeviceNumber.DeviceType);
printf(" Partition Number : %d\n",
DeviceList[k].StorageDeviceNumber.PartitionNumber);
if (memcmp(&DeviceList[k].DeviceInterfaceType,
&GUID_DEVINTERFACE_DISK,
sizeof(GUID)) == 0)
{
HeaderPrinted = FALSE;
VolumeIndex = 0;
for( ; ;)
{
StatusDontCare = GetMountPointsFromDeviceNumber(DeviceList[k].StorageDeviceNumber.DeviceNumber,
VolumeCount,
VolumeList,
&VolumeIndex);
if (StatusDontCare == ERROR_SUCCESS)
{
if (! HeaderPrinted)
{
printf(" Volume Path Names : \n");
HeaderPrinted = TRUE;
}
VolumeMoreInfo = (PVOLUMEMOREINFO)(VolumeList[VolumeIndex].MoreInfo);
p = VolumeMoreInfo->VolumePathNames;
while (*p != 0)
{
#ifdef UNICODE
printf(" %ws\n", p);
#else
printf(" %s\n", p);
#endif
p += _tcslen(p)+1;
}
VolumeIndex++;
} else {
break;
}
}
}
printf("\n");
}
if (VolumeList != NULL)
{
DiscpFreeDeviceInterfaceList(VolumeCount,
VolumeList);
}
}
Free(DeviceList);
}
}
Status = ERROR_SUCCESS;
}
}
}
return(Status);
}
ISDSC_STATUS GetPSKey(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli GetPSKey <Initiator Name> <initiator Port>
// <Id Type> <Id>\n");
{
ISDSC_STATUS Status;
PTCHAR Initiator;
PCHAR Id;
ULONG IdLen;
IKE_IDENTIFICATION_PAYLOAD_TYPE IdType;
ULONG Addr;
PCHAR IdText;
ULONG InitiatorPort;
struct sockaddr_storage sockaddr;
int sockaddrlen;
struct sockaddr_in6 *sockaddr6;
struct sockaddr_in *sockaddr4;
IKE_AUTHENTICATION_INFORMATION AuthInfo;
if (ArgC != 6)
{
Usage(42);
return(ERROR_SUCCESS);
}
Initiator = ArgV[2];
if (*Initiator == TEXT('*'))
{
Initiator = NULL;
}
if (*ArgV[3] == TEXT('*'))
{
InitiatorPort = ISCSI_ALL_INITIATOR_PORTS;
} else {
InitiatorPort = stoi(ArgV[3]);
}
IdType = (IKE_IDENTIFICATION_PAYLOAD_TYPE)stoi(ArgV[4]);
#ifdef UNICODE
IdText = NULL;
Status = DiscpUnicodeToAnsi(ArgV[5],
&IdText,
0);
if (IdText == NULL)
{
Usage(42);
return(ERROR_SUCCESS);
}
#else
IdText = ArgV[5];
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
switch(IdType)
{
case ID_IPV4_ADDR:
{
sockaddrlen = sizeof(sockaddrlen);
Status = WSAStringToAddressA(IdText,
PF_INET,
NULL,
(LPSOCKADDR)&sockaddr,
&sockaddrlen);
if (Status != ERROR_SUCCESS)
{
#ifdef UNICODE
Free(IdText);
#endif
return(Status);
}
sockaddr4 = (struct sockaddr_in *)&sockaddr;
Addr = sockaddr4->sin_addr.S_un.S_addr;
Id = (PCHAR)&Addr;
IdLen = 4;
break;
}
case ID_IPV6_ADDR:
{
sockaddrlen = sizeof(sockaddrlen);
Status = WSAStringToAddressA(IdText,
PF_INET6,
NULL,
(LPSOCKADDR)&sockaddr,
&sockaddrlen);
if (Status != ERROR_SUCCESS)
{
#ifdef UNICODE
Free(IdText);
#endif
return(Status);
}
sockaddr6 = (struct sockaddr_in6 *)&sockaddr;
Id = (PCHAR)&sockaddr6->sin6_addr;
IdLen = 16;
break;
}
case ID_FQDN:
case ID_USER_FQDN:
{
Id = IdText;
IdLen = (ULONG)strlen(IdText);
break;
}
default:
{
printf("Error, only id types ID_IPV4_ADDR (1), ID_FQDN (2), ID_USER_FQDN supported (3)\n");
#ifdef UNICODE
Free(IdText);
#endif
return(ERROR_SUCCESS);
}
}
memset(&AuthInfo, 0, sizeof(IKE_AUTHENTICATION_INFORMATION));
AuthInfo.AuthMethod = IKE_AUTHENTICATION_PRESHARED_KEY_METHOD;
AuthInfo.PsKey.IdType = IdType;
AuthInfo.PsKey.IdLengthInBytes = IdLen;
AuthInfo.PsKey.Id = (PUCHAR)Id;
Status = GetIScsiIKEInfo(Initiator,
InitiatorPort,
NULL,
&AuthInfo);
if (Status == ERROR_SUCCESS)
{
PrintSecurityFlags(" ",
AuthInfo.PsKey.SecurityFlags);
}
}
return(Status);
}
ISDSC_STATUS PSKey(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli PSKey <Initiator Name> <initiator Port> <Security Flags>
// <Id Type> <Id> <Key> <persist>
{
ISDSC_STATUS Status;
PTCHAR Initiator;
ISCSI_SECURITY_FLAGS SecurityFlags;
PCHAR Id;
ULONG IdLen;
IKE_IDENTIFICATION_PAYLOAD_TYPE IdType;
PCHAR Key;
ULONG KeyLength;
ULONG Addr;
PCHAR IdText;
IKE_AUTHENTICATION_INFORMATION IKEAuthInfo;
ULONG InitiatorPort;
BOOLEAN Persist;
struct sockaddr_storage sockaddr;
int sockaddrlen;
struct sockaddr_in6 *sockaddr6;
struct sockaddr_in *sockaddr4;
if (ArgC != 9)
{
Usage(30);
return(ERROR_SUCCESS);
}
Initiator = ArgV[2];
if (*Initiator == TEXT('*'))
{
Initiator = NULL;
}
if (*ArgV[3] == TEXT('*'))
{
InitiatorPort = ISCSI_ALL_INITIATOR_PORTS;
} else {
InitiatorPort = stoi(ArgV[3]);
}
SecurityFlags = stoi(ArgV[4]);
IdType = (IKE_IDENTIFICATION_PAYLOAD_TYPE)stoi(ArgV[5]);
#ifdef UNICODE
IdText = NULL;
Status = DiscpUnicodeToAnsi(ArgV[6],
&IdText,
0);
#else
IdText = ArgV[6];
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
switch(IdType)
{
case ID_IPV4_ADDR:
{
sockaddrlen = sizeof(sockaddr);
Status = WSAStringToAddressA(IdText,
PF_INET,
NULL,
(LPSOCKADDR)&sockaddr,
&sockaddrlen);
if (Status != ERROR_SUCCESS)
{
#ifdef UNICODE
Free(IdText);
#endif
return(Status);
}
sockaddr4 = (struct sockaddr_in *)&sockaddr;
Addr = sockaddr4->sin_addr.S_un.S_addr;
Id = (PCHAR)&Addr;
IdLen = 4;
break;
}
case ID_IPV6_ADDR:
{
sockaddrlen = sizeof(sockaddrlen);
Status = WSAStringToAddressA(IdText,
PF_INET6,
NULL,
(LPSOCKADDR)&sockaddr,
&sockaddrlen);
if (Status != ERROR_SUCCESS)
{
#ifdef UNICODE
Free(IdText);
#endif
return(Status);
}
sockaddr6 = (struct sockaddr_in6 *)&sockaddr;
Id = (PCHAR)&sockaddr6->sin6_addr;
IdLen = 16;
break;
}
case ID_FQDN:
case ID_USER_FQDN:
{
Id = IdText;
IdLen = (ULONG)strlen(IdText);
break;
}
default:
{
printf("Error, only id types ID_IPV4_ADDR (1), ID_FQDN (2), ID_USER_FQDN supported (3)\n");
#ifdef UNICODE
Free(IdText);
#endif
return(ERROR_SUCCESS);
}
}
if (*ArgV[7] == TEXT('*'))
{
Key = NULL;
KeyLength = 0;
} else {
#ifdef UNICODE
Key = NULL;
Status = DiscpUnicodeToAnsi(ArgV[7],
&Key,
0);
#else
Key = ArgV[7];
#endif
KeyLength = (ULONG)strlen(Key);
}
if (Status == ERROR_SUCCESS)
{
Persist = IsTrue(ArgV[8], TRUE);
IKEAuthInfo.AuthMethod = IKE_AUTHENTICATION_PRESHARED_KEY_METHOD;
IKEAuthInfo.PsKey.SecurityFlags = SecurityFlags;
IKEAuthInfo.PsKey.IdType = IdType;
IKEAuthInfo.PsKey.IdLengthInBytes = IdLen;
IKEAuthInfo.PsKey.Id = (PUCHAR)Id;
IKEAuthInfo.PsKey.KeyLengthInBytes = KeyLength;
IKEAuthInfo.PsKey.Key = (PUCHAR)Key;
Status = SetIScsiIKEInfo(Initiator,
InitiatorPort,
&IKEAuthInfo,
Persist);
#ifdef UNICODE
if (Key != NULL)
{
Free(Key);
}
#endif
}
#ifdef UNICODE
Free(IdText);
#endif
}
return(Status);
}
ISDSC_STATUS ReportLUNs(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ReportLUNs <SessionId>
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
PUCHAR Response;
UCHAR Sense[18];
ULONG SenseSize, ResponseSize;
UCHAR ScsiStatus = 0;
if (ArgC != 3)
{
Usage(18);
Status = ERROR_SUCCESS;
} else {
if (StringToSessionId(ArgV[2], &SessionId))
{
SenseSize = 18;
Response = NULL;
ResponseSize = 0;
Status = SendScsiReportLuns(&SessionId,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Response = Alloc(ResponseSize);
if (Response != NULL)
{
Status = SendScsiReportLuns(&SessionId,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_SUCCESS)
{
printf(" ScsiStatus : 0x%x\n"
" Response Buffer Size : 0x%x\n",
ScsiStatus,
ResponseSize);
PrintBuffer(" ",Response, ResponseSize);
}
Free(Response);
}
}
if (Status == ISDSC_SCSI_REQUEST_FAILED)
{
printf(" ScsiStatus : 0x%x\n"
" Sense Buffer Size : 0x%x\n",
ScsiStatus,
SenseSize);
PrintBuffer(" ", Sense, SenseSize);
}
} else {
#ifdef UNICODE
printf("Invalid sessionid: %ws\n", ArgV[2]);
#else
printf("Invalid sessionid: %s\n", ArgV[2]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
}
return(Status);
}
ISDSC_STATUS ReadCapacity(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ReadCapacity <SessionId> <LUN>
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
ULONGLONG LUN;
PUCHAR Response;
UCHAR Sense[18];
ULONG SenseSize, ResponseSize;
UCHAR ScsiStatus = 0;
if (ArgC != 4)
{
Usage(17);
Status = ERROR_SUCCESS;
} else {
if (StringToSessionId(ArgV[2], &SessionId))
{
if (HexStringToULONGLONG(ArgV[3], &LUN, sizeof(ULONGLONG)*2, 0))
{
SenseSize = 18;
Response = NULL;
ResponseSize = 0;
Status = SendScsiReadCapacity(&SessionId,
LUN,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Response = Alloc(ResponseSize);
if (Response != NULL)
{
Status = SendScsiReadCapacity(&SessionId,
LUN,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_SUCCESS)
{
printf(" ScsiStatus : 0x%x\n"
" Response Buffer Size : 0x%x\n",
ScsiStatus,
ResponseSize);
PrintBuffer(" ",Response, ResponseSize);
}
Free(Response);
}
}
if (Status == ISDSC_SCSI_REQUEST_FAILED)
{
printf(" ScsiStatus : 0x%x\n"
" Sense Buffer Size : 0x%x\n",
ScsiStatus,
SenseSize);
PrintBuffer(" ", Sense, SenseSize);
}
} else {
#ifdef UNICODE
printf("Invalid LUN: %ws\n", ArgV[3]);
#else
printf("Invalid LUN: %s\n", ArgV[3]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
} else {
#ifdef UNICODE
printf("Invalid sessionid: %ws\n", ArgV[2]);
#else
printf("Invalid sessionid: %s\n", ArgV[2]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
}
return(Status);
}
ISDSC_STATUS DoScsiInquiry(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ScsiInquiry <SessionId> <LUN> <EvpdCmddt> <PageCode>
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
ULONGLONG LUN;
UCHAR EvpdCmdt, PageCode;
PUCHAR Response;
UCHAR Sense[18];
ULONG SenseSize, ResponseSize;
UCHAR ScsiStatus;
if (ArgC != 6)
{
Usage(16);
Status = ERROR_SUCCESS;
} else {
if (StringToSessionId(ArgV[2], &SessionId))
{
if (HexStringToULONGLONG(ArgV[3], &LUN, sizeof(ULONGLONG)*2, 0))
{
EvpdCmdt = (UCHAR)stoi(ArgV[4]);
PageCode = (UCHAR)stoi(ArgV[5]);
SenseSize = 18;
Response = NULL;
ResponseSize = 0;
Status = SendScsiInquiry(&SessionId,
LUN,
EvpdCmdt,
PageCode,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Response = Alloc(ResponseSize);
if (Response != NULL)
{
Status = SendScsiInquiry(&SessionId,
LUN,
EvpdCmdt,
PageCode,
&ScsiStatus,
&ResponseSize,
Response,
&SenseSize,
Sense);
if (Status == ERROR_SUCCESS)
{
printf(" ScsiStatus : 0x%x\n"
" Response Buffer Size : 0x%x\n",
ScsiStatus,
ResponseSize);
PrintBuffer(" ",Response, ResponseSize);
}
Free(Response);
}
}
if (Status == ISDSC_SCSI_REQUEST_FAILED)
{
printf(" ScsiStatus : 0x%x\n"
" Sense Buffer Size : 0x%x\n",
ScsiStatus,
SenseSize);
PrintBuffer(" ", Sense, SenseSize);
}
} else {
#ifdef UNICODE
printf("Invalid LUN: %ws\n", ArgV[3]);
#else
printf("Invalid LUN: %s\n", ArgV[3]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
} else {
#ifdef UNICODE
printf("Invalid sessionid: %ws\n", ArgV[2]);
#else
printf("Invalid sessionid: %s\n", ArgV[2]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
}
return(Status);
}
ISDSC_STATUS DoLogoutTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli LogoutTarget <SessionId>
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
if (ArgC != 3)
{
Usage(10);
Status = ERROR_SUCCESS;
} else {
if (StringToSessionId(ArgV[2], &SessionId))
{
printf("Logout Target 0x%I64x-0x%I64x\n",
SessionId.AdapterUnique,
SessionId.AdapterSpecific);
Status = LogoutIScsiTarget(&SessionId);
} else {
#ifdef UNICODE
printf("Invalid sessionid: %ws\n", ArgV[2]);
#else
printf("Invalid sessionid: %s\n", ArgV[2]);
#endif
Status = ERROR_INVALID_PARAMETER;
}
}
return(Status);
}
ISDSC_STATUS DoLoginToTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV,
BOOLEAN IsPersistent
)
{
ISDSC_STATUS Status;
BOOLEAN ReportToPNP;
PTCHAR TargetName;
PTCHAR TargetPortalAddress;
USHORT TargetPortalSocket;
PTCHAR InitiatorInstance;
ISCSI_UNIQUE_SESSION_ID SessionId;
ISCSI_UNIQUE_SESSION_ID ConnectionId;
ISCSI_TARGET_PORTAL TargetPortal = { 0 };
ISCSI_LOGIN_OPTIONS LoginOptions;
ISCSI_SECURITY_FLAGS SecurityFlags;
ULONG MappingCount;
PISCSI_TARGET_MAPPING Mapping;
ULONG i, ArgCIndex;
ULONG PortNumber;
int ArgCExpected;
PCHAR Key;
ULONG KeyLength;
ULONG SizeNeeded;
ULONG x;
BOOLEAN b;
HRESULT hr;
if (ArgC < 20)
{
Usage(IsPersistent ? 11 : 9);
Status = ERROR_SUCCESS;
} else {
TargetName = ArgV[2];
ReportToPNP = TRUE;
TargetPortalAddress = NULL;
TargetPortalSocket = 0;
InitiatorInstance = NULL;
ReportToPNP = IsTrue(ArgV[3], TRUE);
if (*ArgV[4] != TEXT('*'))
{
TargetPortalAddress = ArgV[4];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
}
if ((TargetPortalAddress != NULL) && (*ArgV[5] != TEXT('*')))
{
TargetPortalSocket = (USHORT)stoi(ArgV[5]);
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = TargetPortalSocket;
*TargetPortal.SymbolicName = 0;
} else if (! ((TargetPortalAddress == NULL) &&
(*ArgV[5] == TEXT('*')))) {
printf("Portal address and socket must be specified\n");
return(ERROR_INVALID_PARAMETER);
}
if (*ArgV[6] != TEXT('*'))
{
InitiatorInstance = ArgV[6];
}
if (*ArgV[7] != TEXT('*'))
{
PortNumber = stoi(ArgV[7]);
} else {
PortNumber = ISCSI_ANY_INITIATOR_PORT;
}
SecurityFlags = stoi(ArgV[8]);
ParseLoginOptions(&LoginOptions,
ArgV,
ArgC,
9);
if (*ArgV[18] == TEXT('*'))
{
Key = NULL;
KeyLength = 0;
} else {
#ifdef UNICODE
Key = NULL;
DiscpUnicodeToAnsi(ArgV[18],
&Key,
0);
#else
Key = ArgV[18];
#endif
KeyLength = (ULONG)strlen(Key) + 1;
}
MappingCount = stoi(ArgV[19]);
ArgCExpected = 20 + (MappingCount * 4);
if (ArgC != ArgCExpected)
{
Usage(IsPersistent ? 11 : 9);
return(ERROR_SUCCESS);
}
if (MappingCount != 0)
{
SizeNeeded = sizeof(ISCSI_TARGET_MAPPING) +
MappingCount * sizeof(SCSI_LUN_LIST);
Mapping = (PISCSI_TARGET_MAPPING)Alloc(SizeNeeded) ;
if (Mapping == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
ArgCIndex = 20;
*Mapping->InitiatorName = 0;
*Mapping->TargetName = 0;
*Mapping->OSDeviceName = 0;
Mapping->OSBusNumber = stoi(ArgV[ArgCIndex+1]);
Mapping->OSTargetNumber = stoi(ArgV[ArgCIndex+2]);
Mapping->LUNCount = MappingCount;
Mapping->LUNList = (PSCSI_LUN_LIST)OffsetToPtr(Mapping,
sizeof(ISCSI_TARGET_MAPPING));
for (i = 0; i < MappingCount; i++)
{
b = stoiDForLogicalUnit(ArgV[ArgCIndex],
&Mapping->LUNList[i].TargetLUN);
if (b == FALSE)
{
printf("Target LUN must be in 0x0123456789abcdef format\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++; // bus
x = stoi(ArgV[ArgCIndex]);
if (x != Mapping->OSBusNumber)
{
printf("OSBus number must be the same for all LUNs\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++; // target
x = stoi(ArgV[ArgCIndex]);
if (x != Mapping->OSTargetNumber)
{
printf("OSTarget number must be the same for all LUNs\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++;
Mapping->LUNList[i].OSLUN = stoi(ArgV[ArgCIndex]);
ArgCIndex++;
}
} else {
Mapping = NULL;
}
#ifdef UNICODE
printf("LoginTarget to %ws on %ws to %ws/%d\n",
TargetName,
InitiatorInstance ? InitiatorInstance : L"<no init instance>",
TargetPortalAddress ? TargetPortal.Address : L"<no portal>",
TargetPortalAddress ? TargetPortal.Socket : 0
);
#else
printf("LoginTarget to %s on %s to %s/%d\n",
TargetName,
InitiatorInstance ? InitiatorInstance : "<no init instance>",
TargetPortalAddress ? TargetPortal.Address : "<no portal>",
TargetPortalAddress ? TargetPortal.Socket : 0
);
#endif
Status = LoginIScsiTarget(TargetName,
ReportToPNP ? FALSE : TRUE,
InitiatorInstance,
PortNumber, // PortNUmber
TargetPortalAddress ? &TargetPortal : NULL,
SecurityFlags,
Mapping, // Mappings
&LoginOptions, // LoginOptions
KeyLength,
Key,
IsPersistent,
&SessionId,
&ConnectionId);
if (! IsPersistent)
{
if (Status == ERROR_SUCCESS)
{
printf("Session Id is 0x%I64x-0x%I64x\n",
SessionId.AdapterUnique,
SessionId.AdapterSpecific);
printf("Connection Id is 0x%I64x-0x%I64x\n",
ConnectionId.AdapterUnique,
ConnectionId.AdapterSpecific);
}
}
if (Mapping != NULL)
{
Free(Mapping);
}
}
return(Status);
}
ISDSC_STATUS TryLoginToTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli LoginTarget <TargetName> <ReportToPNP>
// <TargetPortalAddress> <TargetPortalSocket>
// <InitiatorInstance> <Port number> <Security Flags>
// <Header Digest> <Data Digest>
// <Max Connections> <DefaultTime2Wait>
// <DefaultTime2Retain> <Username> <Password>
// <AuthType> <Key>
// <Mapping Count> <Target Lun> <OS Bus> <Os Target>
// <OS Lun> ...
//
{
ISDSC_STATUS Status;
Status = DoLoginToTarget(ArgC,
ArgV,
FALSE);
return(Status);
}
ISDSC_STATUS PersistentLoginTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli PersistentLoginTarget <TargetName> <ReportToPNP>
// <TargetPortalAddress> <TargetPortalSocket>
// <InitiatorInstance> <Port number> <Security Flags>
// <Header Digest> <Data Digest>
// <Max Connections> <DefaultTime2Wait>
// <DefaultTime2Retain> <Username> <Password>
// <AuthType> <Key>
// <Mapping Count> <Target Lun> <OS Bus> <Os Target>
// <OS Lun> ...
//
{
ISDSC_STATUS Status;
Status = DoLoginToTarget(ArgC,
ArgV,
TRUE);
return(Status);
}
ISDSC_STATUS RemovePersistentTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli RemovePersistentTarget <Initiator Name> <TargetName>\n"
// printf(" <Port Number> \n");
// printf(" <Target Portal Address> \n");
// printf(" <Target Portal Socket> \n");
{
ISDSC_STATUS Status;
PTCHAR I;
ISCSI_TARGET_PORTAL TargetPortal;
PISCSI_TARGET_PORTAL TargetPortalPtr;
ULONG PortNumber;
HRESULT hr;
if (ArgC != 7)
{
Usage(13);
Status = ERROR_SUCCESS;
} else {
if (*ArgV[2] == TEXT('*'))
{
I = NULL;
} else {
I = ArgV[2];
}
if (*ArgV[4] == TEXT('*'))
{
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
} else {
PortNumber = stoi(ArgV[4]);
}
if (*ArgV[5] == TEXT('*'))
{
//
// Both empty and NULL portal have the same effect
//
TargetPortalPtr = NULL;
#if 0
TargetPortalPtr = &TargetPortal;
memset(TargetPortalPtr, 0, sizeof(ISCSI_TARGET_PORTAL));
#endif
} else {
if (_tcslen(ArgV[5]) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
ArgV[5]);
TargetPortal.Socket = (USHORT)stoi(ArgV[6]);
*TargetPortal.SymbolicName = 0;
TargetPortalPtr = &TargetPortal;
}
Status = RemoveIScsiPersistentTarget(I,
PortNumber,
ArgV[3],
TargetPortalPtr);
}
return(Status);
}
ISDSC_STATUS ListPersistentTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli ListPersistentTargets\n");
{
ISDSC_STATUS Status;
ULONG Count;
PPERSISTENT_ISCSI_LOGIN_INFO LoginInfo, LoginInfoArray;
ULONG i;
ULONG SizeNeeded;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
Count = 0;
SizeNeeded = 0;
Status = ReportIScsiPersistentLogins(&Count,
NULL,
&SizeNeeded);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
printf("Total of %d peristent targets\n",
Count
);
LoginInfoArray = Alloc(SizeNeeded);
if (LoginInfoArray != NULL)
{
Status = ReportIScsiPersistentLogins(&Count,
LoginInfoArray,
&SizeNeeded);
if (Status == ERROR_SUCCESS)
{
for (i = 0; i < Count; i++)
{
LoginInfo = &LoginInfoArray[i];
#ifdef UNICODE
printf(" Target Name : %ws\n"
" Address and Socket : %ws %d\n"
" Session Type : %s\n"
" Initiator Name : %ws\n",
#else
printf(" Target Name : %s\n"
" Address and Socket : %s %d\n"
" Session Type : %s\n"
" Initiator Name : %s\n",
#endif
LoginInfo->TargetName,
*(LoginInfo->TargetPortal.Address) == 0 ? TEXT("*") : LoginInfo->TargetPortal.Address,
LoginInfo->TargetPortal.Socket,
LoginInfo->IsInformationalSession ? "Informational" : "Data",
LoginInfo->InitiatorInstance
);
if (LoginInfo->InitiatorPortNumber == ISCSI_ANY_INITIATOR_PORT)
{
printf(" Port Number : <Any Port>\n");
} else {
printf(" Port Number : %d\n",
LoginInfo->InitiatorPortNumber
);
}
PrintSecurityFlags(" ", LoginInfo->SecurityFlags);
PrintLoginOptions(" ",
&LoginInfo->LoginOptions);
if (LoginInfo->Mappings != NULL)
{
PrintTargetMapping(LoginInfo->Mappings);
}
printf("\n");
}
}
Free(LoginInfoArray);
}
}
return(Status);
}
ISDSC_STATUS GetTargetInfo(
IN __in PTCHAR TargetName,
IN __in_opt PTCHAR DiscoveryMechanism,
IN TARGET_INFORMATION_CLASS InfoClass,
IN OUT PULONG BufferSize,
OUT PVOID *Buffer
)
{
ISDSC_STATUS Status;
PVOID b;
ULONG SizeNeeded;
SizeNeeded = 0;
Status = GetIScsiTargetInformation(TargetName,
DiscoveryMechanism,
InfoClass,
&SizeNeeded,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
b = Alloc(SizeNeeded);
if (b == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
Status = GetIScsiTargetInformation(TargetName,
DiscoveryMechanism,
InfoClass,
&SizeNeeded,
b);
if (Status == ERROR_SUCCESS)
{
*Buffer = b;
*BufferSize = SizeNeeded;
} else {
Free(b);
}
}
return(Status);
}
void PrintPortalGroups(
ULONG Count,
PISCSI_TARGET_PORTAL_GROUP PortalGroups,
ULONG Size
)
{
PISCSI_TARGET_PORTAL_GROUP p;
ULONG SizeUsed, i, j;
p = PortalGroups;
for (i = 0; i < Count; i++)
{
printf(" Group %d has %d portals\n",
i,
p->Count
);
if (p->Count == 0)
{
SizeUsed = (FIELD_OFFSET(ISCSI_TARGET_PORTAL_GROUP,
Portals) +3) & ~3;
} else {
SizeUsed = ((sizeof(ISCSI_TARGET_PORTAL_GROUP) +
(p->Count-1) * sizeof(ISCSI_TARGET_PORTAL))+3) & ~3;
}
if (SizeUsed <= Size)
{
for (j = 0; j < p->Count; j++)
{
#ifdef UNICODE
printf(" Address and Socket : %ws %d\n"
" Symbolic Name : %ws\n",
#else
printf(" Address and Socket : %s %d\n"
" Symbolic Name : %s\n",
#endif
p->Portals[j].Address,
p->Portals[j].Socket,
p->Portals[j].SymbolicName
);
}
Size -= SizeUsed;
p = (PISCSI_TARGET_PORTAL_GROUP)((PUCHAR)p + SizeUsed);
} else {
break;
}
}
}
ISDSC_STATUS TargetInfo(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli TargetInfo <TargetName> [DiscoveryMechanism]
{
PTCHAR DiscoveryMechanism;
ULONG Count;
ISDSC_STATUS Status;
ULONG Size;
PVOID Buffer;
TCHAR m[MAX_PATH];
if ((ArgC != 3) && (ArgC != 4))
{
Usage(8);
return(ERROR_SUCCESS);
} else {
if (ArgC == 3)
{
DiscoveryMechanism = NULL;
} else if (ArgV[3][0] == TEXT('*')) {
DiscoveryMechanism = NULL;
} else {
DiscoveryMechanism = ArgV[3];
}
}
#ifdef UNICODE
printf("Get Target information for %ws discovered by %ws\n",
#else
printf("Get Target information for %s discovered by %s\n",
#endif
ArgV[2],
DiscoveryMechanism != NULL ? DiscoveryMechanism : TEXT("<all mechanisms>"));
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
DiscoveryMechanisms,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size > 0)
{
PrintStringList(" Discovery Mechanisms :",
" ",
Buffer,
Size);
} else {
printf(" Discovery Mechanisms: <This List is Empty>\n");
}
Free(Buffer);
}
if (DiscoveryMechanism != NULL)
{
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
ProtocolType,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
PCHAR ProtocolList[] = { "iSCSI TCP Protocol", "Unknown" };
TARGETPROTOCOLTYPE ProtocolType;
ProtocolType = *((PTARGETPROTOCOLTYPE)Buffer);
if (ProtocolType != ISCSI_TCP_PROTOCOL_TYPE)
{
ProtocolType = 1;
}
printf(" Protocol Type : %s\n",
ProtocolList[ProtocolType]);
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Protocol Type Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Protocol Type Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
TargetAlias,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
#ifdef UNICODE
printf(" Target Alias : %ws\n",
#else
printf(" Target Alias : %s\n",
#endif
(PTCHAR)Buffer);
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Target Alias Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Target Alias Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
PortalGroups,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size > 0)
{
PISCSI_TARGET_PORTAL_GROUP p;
Count = *((PULONG)Buffer);
p = (PISCSI_TARGET_PORTAL_GROUP)((PUCHAR)Buffer + sizeof(ULONG));
printf(" PortalGroups : %d portal groups\n",
Count
);
PrintPortalGroups(
Count,
p,
Size);
} else {
printf(" PortalGroups : <This List Is Empty>\n");
}
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Portal Groups Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Portal Groups Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
InitiatorName,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size > 0)
{
#ifdef UNICODE
printf(" Initiator Name : %ws\n",
(PWSTR)Buffer);
#else
printf(" Initiator Name : %s\n",
(PSTR)Buffer);
#endif
} else {
printf(" Initiator Name : <Empty>\n");
}
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Initiator List Failed: %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Initiator List Failed: %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
TargetFlags,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size == sizeof(ISCSI_TARGET_FLAGS))
{
ISCSI_TARGET_FLAGS TargetFlags;
TargetFlags = *((PISCSI_TARGET_FLAGS)Buffer);
printf(" Target Flags : 0x%x\n",
TargetFlags);
if (TargetFlags & ISCSI_TARGET_FLAG_HIDE_STATIC_TARGET)
{
printf(" Target is hidden until dynamically discovered\n");
}
}
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Target Flags Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Target Flags Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
LoginOptions,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size >= sizeof(ISCSI_LOGIN_OPTIONS))
{
PISCSI_LOGIN_OPTIONS LoginOptions;
LoginOptions = (PISCSI_LOGIN_OPTIONS)Buffer;
PrintLoginOptions(" ",
LoginOptions);
}
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Login Options Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Login Options Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = GetTargetInfo(ArgV[2],
DiscoveryMechanism,
PersistentTargetMappings,
&Size,
&Buffer);
if (Status == ERROR_SUCCESS)
{
if (Size >= sizeof(ISCSI_TARGET_MAPPING))
{
PISCSI_TARGET_MAPPING Mapping;
Mapping = (PISCSI_TARGET_MAPPING)Buffer;
PrintTargetMapping(
Mapping);
}
Free(Buffer);
} else {
#ifdef UNICODE
printf(" Target Mappings Failed : %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf(" Target Mappings Failed : %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
}
Status = ERROR_SUCCESS;
}
printf("\n");
return(Status);
}
ISDSC_STATUS DoAddConnection(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli AddConnection <SessionId> <initiator instance>
// <Port Number> <Target Portal Address>
// <Target Portal Socket> <Security Flags>
// <Header Digest> <Data Digest>
// <Max Connections> <DefaultTime2Wait>
// <DefaultTime2Retain> <Username> <Password>
// <AuthType> <Key>
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR TargetPortalAddress;
ULONG PortNumber;
USHORT TargetPortalSocket;
ISCSI_LOGIN_OPTIONS LoginOptions;
ISCSI_SECURITY_FLAGS SecurityFlags;
PCHAR Key;
ULONG KeyLength = 0;
ISCSI_UNIQUE_CONNECTION_ID ConnectionId;
PTCHAR InitiatorName;
HRESULT hr;
if (ArgC != 18)
{
Usage(14);
return(ERROR_SUCCESS);
}
if (! StringToSessionId(ArgV[2], &SessionId))
{
Usage(14);
return(ERROR_SUCCESS);
}
if (*ArgV[3] != TEXT('*'))
{
InitiatorName = ArgV[3];
} else {
InitiatorName = NULL;
}
if (*ArgV[4] == TEXT('*'))
{
PortNumber = ISCSI_ANY_INITIATOR_PORT;
} else {
PortNumber = stoi(ArgV[4]);
}
if (*ArgV[5] != TEXT('*'))
{
TargetPortalAddress = ArgV[5];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
} else {
TargetPortalAddress = NULL;
}
if ((TargetPortalAddress != NULL) && ((*ArgV[6] != TEXT('*'))))
{
TargetPortalSocket = (USHORT)stoi(ArgV[6]);
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = TargetPortalSocket;
*TargetPortal.SymbolicName = 0;
} else {
TargetPortalAddress = NULL;
}
SecurityFlags = stoi(ArgV[7]);
ParseLoginOptions(&LoginOptions,
ArgV,
ArgC,
8);
if (*ArgV[17] == TEXT('*'))
{
Key = NULL;
KeyLength = 0;
Status = ERROR_SUCCESS;
} else {
#ifdef UNICODE
Key = NULL;
Status = DiscpUnicodeToAnsi(ArgV[17],
&Key,
0);
#else
Key = ArgV[17];
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
KeyLength = (ULONG)strlen(Key) + 1;
}
}
if (Status == ERROR_SUCCESS)
{
Status = AddIScsiConnection(&SessionId,
InitiatorName,
PortNumber,
TargetPortalAddress ? &TargetPortal : NULL,
SecurityFlags,
&LoginOptions,
KeyLength,
Key,
&ConnectionId);
#ifdef UNICODE
if (Key != NULL)
{
Free(Key);
}
#endif
}
return(Status);
}
ISDSC_STATUS DoRemoveConnection(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli RemoveConnection <SessionId> <ConnectionId> \n");
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
ISCSI_UNIQUE_CONNECTION_ID ConnectionId;
if (ArgC != 4)
{
Usage(15);
return(ERROR_SUCCESS);
}
if (! StringToSessionId(ArgV[2], &SessionId))
{
Usage(15);
return(ERROR_SUCCESS);
}
if (! StringToSessionId(ArgV[3], &ConnectionId))
{
Usage(15);
return(ERROR_SUCCESS);
}
Status = RemoveIScsiConnection(&SessionId,
&ConnectionId);
return(Status);
}
ISDSC_STATUS DoReportInitiatorList(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ListInitiators
{
ISDSC_STATUS Status;
PTCHAR Buffer,b = NULL;
ULONG BufferSize;
UNREFERENCED_PARAMETER(ArgV);
if (ArgC != 2)
{
Usage(20);
Status = ERROR_SUCCESS;
} else {
BufferSize = 0;
Buffer = NULL;
Status = ReportIScsiInitiatorList(
&BufferSize,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Buffer = Alloc(BufferSize * sizeof(TCHAR));
if (Buffer == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
b = Buffer;
Status = ReportIScsiInitiatorList(
&BufferSize,
Buffer);
}
if (Status == ERROR_SUCCESS)
{
printf("Initiators List:\n");
while (*Buffer != 0)
{
#ifdef UNICODE
printf(" %ws\n", Buffer);
#else
printf(" %s\n", Buffer);
#endif
while (*Buffer != 0)
{
Buffer++;
}
Buffer++;
}
}
if (b != NULL)
{
Free(b);
}
}
return(Status);
}
ISDSC_STATUS DoReportActiveIScsiTargetMappings(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ReportTargetMappings
{
ISDSC_STATUS Status;
ULONG MappingCount, BufferSize;
PISCSI_TARGET_MAPPING Mapping, MappingX;
ULONG i;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
BufferSize = 0;
Status = ReportActiveIScsiTargetMappings(&BufferSize,
&MappingCount,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
MappingX = (PISCSI_TARGET_MAPPING)Alloc(BufferSize);
if (MappingX != NULL)
{
Status = ReportActiveIScsiTargetMappings(&BufferSize,
&MappingCount,
MappingX);
if (Status == ERROR_SUCCESS)
{
printf("Total of %d mappings returned\n", MappingCount);
Mapping = MappingX;
for (i = 0; i < MappingCount; i++)
{
PrintTargetMapping(Mapping);
Mapping++;
}
}
Free(MappingX);
}
} else if (Status == ERROR_SUCCESS) {
printf("No mappings\n");
}
return(Status);
}
ISDSC_STATUS ListTargets(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ListTargets <ForceUpdate>
{
ISDSC_STATUS Status;
BOOLEAN ForceUpdate;
PTCHAR Buffer,b = NULL;
ULONG BufferSize;
if ((ArgC != 3) && (ArgC != 2))
{
Usage(6);
Status = ERROR_SUCCESS;
} else {
if (ArgC == 3)
{
ForceUpdate = IsTrue(ArgV[2], FALSE);
} else {
ForceUpdate = FALSE;
}
BufferSize = 0;
Buffer = NULL;
Status = ReportIScsiTargets(ForceUpdate,
&BufferSize,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Buffer = Alloc(BufferSize * sizeof(TCHAR));
if (Buffer == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
b = Buffer;
Status = ReportIScsiTargets(ForceUpdate,
&BufferSize,
Buffer);
}
if (Status == ERROR_SUCCESS)
{
printf("Targets List:\n");
while (*Buffer != 0)
{
#ifdef UNICODE
printf(" %ws\n", Buffer);
#else
printf(" %s\n", Buffer);
#endif
while (*Buffer != 0)
{
Buffer++;
}
Buffer++;
}
}
}
if (b != NULL)
{
Free(b);
}
return(Status);
}
ISDSC_STATUS RefreshTargetPortal(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli RefreshTargetPortal <TargetPortalAddress>
// <TargetPortalSocket> [HBAName]
// [PortNumber]
{
ISDSC_STATUS Status;
PTCHAR TargetPortalAddress;
PTCHAR TargetPortalSocket;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR HBAName;
ULONG PortNumber;
HRESULT hr;
if ((ArgC < 4) || (ArgC > 6))
{
Usage(5);
Status = ERROR_SUCCESS;
} else {
TargetPortalAddress = ArgV[2];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
TargetPortalSocket = ArgV[3];
if (ArgC > 4)
{
HBAName = ArgV[4];
if (*HBAName == TEXT('*'))
{
HBAName = NULL;
}
if (ArgC > 5)
{
if (*ArgV[5] == TEXT('*'))
{
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
} else {
PortNumber = stoi(ArgV[5]);
}
} else {
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
} else {
HBAName = NULL;
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = (USHORT)stoi(TargetPortalSocket);
Status = RefreshIScsiSendTargetPortal(HBAName,
PortNumber,
&TargetPortal);
}
return(Status);
}
ISDSC_STATUS ListTargetPortals(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli ListTargetPortals
{
ISDSC_STATUS Status;
ULONG Count;
PISCSI_TARGET_PORTAL_INFO_EX PortalInfoArray, PortalInfo;
ULONG i;
ULONG SizeNeeded;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
Count = 0;
Status = ReportIScsiSendTargetPortalsEx(&Count,
&SizeNeeded,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
PortalInfoArray = Alloc(SizeNeeded);
if (PortalInfoArray != NULL)
{
Status = ReportIScsiSendTargetPortalsEx(&Count,
&SizeNeeded,
PortalInfoArray);
if (Status == ERROR_SUCCESS)
{
printf("Total of %d portals are persisted:\n\n", Count);
for (i = 0; i < Count; i++)
{
PortalInfo = &PortalInfoArray[i];
#ifdef UNICODE
printf(" Address and Socket : %ws %d\n"
" Symbolic Name : %ws\n"
" Initiator Name : %ws\n",
#else
printf(" Address and Socket : %s %d\n"
" Symbolic Name : %s\n"
" Initiator Name : %s\n",
#endif
PortalInfo->Address,
PortalInfo->Socket,
PortalInfo->SymbolicName,
PortalInfo->InitiatorName
);
if (PortalInfo->InitiatorPortNumber == ISCSI_ANY_INITIATOR_PORT)
{
printf(" Port Number : <Any Port>\n");
} else {
printf(" Port Number : %d\n",
PortalInfo->InitiatorPortNumber);
}
PrintSecurityFlags(" ",
PortalInfo->SecurityFlags);
PrintLoginOptions(" ",
&PortalInfo->LoginOptions);
printf("\n");
}
}
Free(PortalInfoArray);
}
}
return(Status);
}
ISDSC_STATUS RemoveTargetPortal(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli RemoveTargetPortal <TargetPortalAddress> <TargetPortalSocket>
// [HBA Name] [PortNumber]
//
{
ISDSC_STATUS Status;
PTCHAR TargetPortalAddress;
PTCHAR TargetPortalSocket;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR HBAName;
ULONG PortNumber;
HRESULT hr;
if ((ArgC < 4) || (ArgC > 6))
{
Usage(4);
Status = ERROR_SUCCESS;
} else {
TargetPortalAddress = ArgV[2];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
TargetPortalSocket = ArgV[3];
if (ArgC > 4)
{
HBAName = ArgV[4];
if (*HBAName == TEXT('*'))
{
HBAName = NULL;
}
if (ArgC > 5)
{
if (*ArgV[5] == TEXT('*'))
{
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
} else {
PortNumber = stoi(ArgV[5]);
}
} else {
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
} else {
HBAName = NULL;
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = (USHORT)stoi(TargetPortalSocket);
Status = RemoveIScsiSendTargetPortal(HBAName,
PortNumber,
&TargetPortal);
}
return(Status);
}
ISDSC_STATUS AddTargetPortal(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli AddTargetPortal <TargetPortalAddress> <TargetPortalSocket>
// [HBA Name] [PortNumber]
// printf(" <Security Flags>\n");
// printf(" <Login Flags> <Header Digest> <Data Digest> \n");
// printf(" <Max Connections> <DefaultTime2Wait>\n");
// printf(" <DefaultTime2Retain> <Username>
// <Password> <AuthType>\n");
{
ISDSC_STATUS Status;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR TargetPortalAddress, TargetPortalSocket, HBAName;
ULONG PortNumber;
PISCSI_LOGIN_OPTIONS LoginOptions = NULL;
ISCSI_LOGIN_OPTIONS LO;
ISCSI_SECURITY_FLAGS SecurityFlags = 0;
HRESULT hr;
if ((ArgC != 4) && (ArgC < 16))
{
Usage(3);
Status = ERROR_SUCCESS;
} else {
TargetPortalAddress = ArgV[2];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
TargetPortalSocket = ArgV[3];
if (ArgC > 4)
{
HBAName = ArgV[4];
if (*HBAName == TEXT('*'))
{
HBAName = NULL;
}
if (ArgC > 5)
{
if (*ArgV[5] == TEXT('*'))
{
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
} else {
PortNumber = stoi(ArgV[5]);
}
SecurityFlags = stoi(ArgV[6]);
if (ArgC > 7)
{
ParseLoginOptions(&LO,
ArgV,
ArgC,
7);
LoginOptions = &LO;
} else {
LoginOptions = NULL;
}
} else {
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
} else {
HBAName = NULL;
PortNumber = ISCSI_ALL_INITIATOR_PORTS;
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = (USHORT)stoi(TargetPortalSocket);
*TargetPortal.SymbolicName = 0;
Status = AddIScsiSendTargetPortal(HBAName,
PortNumber,
LoginOptions,
SecurityFlags,
&TargetPortal);
}
return(Status);
}
ISDSC_STATUS RemoveTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli RemoveTarget <TargetName>
{
ISDSC_STATUS Status;
PTCHAR TargetName;
if (ArgC != 3)
{
Usage(2);
Status = ERROR_SUCCESS;
return(Status);
} else {
TargetName = ArgV[2];
}
Status = RemoveIScsiStaticTarget(TargetName);
return(Status);
}
ISDSC_STATUS AddTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli AddTarget <TargetName> <TargetAlias> <TargetPortalAddress>
// <TargetPortalSocket> <Target flags>
// <Persist> <Header Digest> <Data Digest>
// <Max Connections> <DefaultTime2Wait>
// <DefaultTime2Retain> <Username> <Password>
// <AuthType>
// <Mapping Count> <Target Lun> <OS Bus> <Os Target>
// <OS Lun> ...
{
ISDSC_STATUS Status;
ISCSI_TARGET_PORTAL_GROUP PortalGroup;
PTCHAR TargetName, TargetAlias, TargetPortalAddress;
PTCHAR TargetPortalSocket;
ISCSI_LOGIN_OPTIONS LoginOptions;
BOOLEAN Persist;
ULONG MappingCount;
PISCSI_TARGET_MAPPING Mapping;
int ArgCExpected, ArgCIndex;
ISCSI_TARGET_FLAGS TargetFlags;
ULONG i, SizeNeeded;
ULONG x;
BOOLEAN b;
HRESULT hr;
if (ArgC < 18)
{
Usage(1);
Status = ERROR_SUCCESS;
} else {
TargetName = ArgV[2];
if (*ArgV[3] == TEXT('*'))
{
TargetAlias = NULL;
} else {
TargetAlias = ArgV[3];
}
if ((*ArgV[4] != TEXT('*')) && (*ArgV[5] != TEXT('*')))
{
TargetPortalAddress = ArgV[4];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
TargetPortalSocket = ArgV[5];
PortalGroup.Count = 1;
*PortalGroup.Portals[0].SymbolicName = 0;
hr = StringCchCopy(PortalGroup.Portals[0].Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
PortalGroup.Portals[0].Socket = (USHORT)stoi(TargetPortalSocket);
} else {
PortalGroup.Count = 0;
*PortalGroup.Portals[0].Address = 0;
}
TargetFlags = stoi(ArgV[6]);
Persist = IsTrue(ArgV[7], TRUE);
ParseLoginOptions(&LoginOptions,
ArgV,
ArgC,
8);
MappingCount = stoi(ArgV[17]);
ArgCExpected = 18 + (MappingCount * 4);
if (ArgC != ArgCExpected)
{
Usage(1);
return(ERROR_SUCCESS);
}
if (MappingCount != 0)
{
SizeNeeded = sizeof(ISCSI_TARGET_MAPPING) +
MappingCount * sizeof(SCSI_LUN_LIST);
Mapping = (PISCSI_TARGET_MAPPING)Alloc(SizeNeeded) ;
if (Mapping == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
ArgCIndex = 18;
*Mapping->InitiatorName = 0;
*Mapping->TargetName = 0;
*Mapping->OSDeviceName = 0;
Mapping->OSBusNumber = stoi(ArgV[ArgCIndex+1]);
Mapping->OSTargetNumber = stoi(ArgV[ArgCIndex+2]);
Mapping->LUNCount = MappingCount;
Mapping->LUNList = (PSCSI_LUN_LIST)OffsetToPtr(Mapping,
sizeof(ISCSI_TARGET_MAPPING));
for (i = 0; i < MappingCount; i++)
{
b = stoiDForLogicalUnit(ArgV[ArgCIndex],
&Mapping->LUNList[i].TargetLUN);
if (b == FALSE)
{
printf("Target LUN must be in 0x0123456789abcdef format\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++;
x = stoi(ArgV[ArgCIndex]);
if (x != Mapping->OSBusNumber)
{
printf("OSBus number must be the same for all LUNs\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++; // target
x = stoi(ArgV[ArgCIndex]);
if (x != Mapping->OSTargetNumber)
{
printf("OSTarget number must be the same for all LUNs\n");
return(ERROR_INVALID_PARAMETER);
}
ArgCIndex++;
Mapping->LUNList[i].OSLUN = stoi(ArgV[ArgCIndex]);
ArgCIndex++;
}
} else {
Mapping = NULL;
}
Status = AddIScsiStaticTarget(TargetName,
TargetAlias,
TargetFlags, // TargetFlags
Persist, // Persist
Mapping, // Mappings
&LoginOptions, // LoginOptions
PortalGroup.Count == 0 ?
NULL :
&PortalGroup);
if (Mapping != NULL)
{
Free(Mapping);
}
}
return(Status);
}
ISDSC_STATUS AddiSNSServerX(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli AddiSNSServer <Server name>
{
ISDSC_STATUS Status;
PTCHAR ServerName;
if (ArgC != 3)
{
Usage(21);
return(ERROR_SUCCESS);
}
ServerName = ArgV[2];
Status = AddISNSServer(ServerName);
return(Status);
}
ISDSC_STATUS RemoveiSNSServerX(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli RemoveiSNSServer <Server name>
{
ISDSC_STATUS Status;
PTCHAR ServerName;
if (ArgC != 3)
{
Usage(22);
return(ERROR_SUCCESS);
}
ServerName = ArgV[2];
Status = RemoveISNSServer(ServerName);
return(Status);
}
ISDSC_STATUS RefreshiSNSServer(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// iscsicli RefreshiSNSServer <Server name>
{
ISDSC_STATUS Status;
PTCHAR ServerName;
if (ArgC != 3)
{
Usage(23);
return(ERROR_SUCCESS);
}
if (*ArgV[2] == TEXT('*'))
{
ServerName = NULL;
} else {
ServerName = ArgV[2];
}
Status = RefreshISNSServer(ServerName);
return(Status);
}
ISDSC_STATUS ListiSNSServers(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli ListiSNSServer\n");
{
ISDSC_STATUS Status;
ULONG SizeNeeded, Size, Len;
PTCHAR Buffer, b;
UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);
SizeNeeded = 0;
Status = ReportISNSServerList(&SizeNeeded,
NULL);
if (Status == ERROR_INSUFFICIENT_BUFFER)
{
Buffer = (PTCHAR)Alloc(SizeNeeded * sizeof(TCHAR));
if (Buffer != NULL)
{
Status = ReportISNSServerList(&SizeNeeded,
Buffer);
if (Status == ERROR_SUCCESS)
{
Len = 0;
b = (PTCHAR)Buffer;
while (Len < SizeNeeded)
{
b = &Buffer[Len];
Size = (ULONG)(_tcslen(b) + 1);
#ifdef UNICODE
printf(" %ws\n", b);
#else
printf(" %s\n", b);;
#endif
Len += Size;
}
}
Free(Buffer);
}
} else if (Status == ERROR_SUCCESS) {
printf("No SNS Servers\n");
}
return(Status);
}
ISDSC_STATUS BuildLoginOptionsForCHAP(
IN __in PTSTR CHAPUsername,
IN __in PTSTR CHAPPassword,
OUT PISCSI_LOGIN_OPTIONS *LoginOptionsPtr
)
/*++
Routine Description:
This routine will allocate a login options structure and build it
to contain the CHAP username and password needed for one way CHAP
Arguments:
CHAPUsername is the chap username to use
CHAPPassword is the chap password to use
*LoginOptionsPtr returns with the filled in login option structure
Return Value:
ERROR_SUCCESS or error code
--*/
{
ISDSC_STATUS Status;
PISCSI_LOGIN_OPTIONS LoginOptions;
PTCHAR Secret;
LoginOptions = Alloc(sizeof(ISCSI_LOGIN_OPTIONS));
if (LoginOptions != NULL)
{
memset(LoginOptions, 0, sizeof(ISCSI_LOGIN_OPTIONS));
LoginOptions->Version = ISCSI_LOGIN_OPTIONS_VERSION;
LoginOptions->InformationSpecified = ISCSI_LOGIN_OPTIONS_USERNAME |
ISCSI_LOGIN_OPTIONS_PASSWORD |
ISCSI_LOGIN_OPTIONS_AUTH_TYPE;
LoginOptions->AuthType = ISCSI_CHAP_AUTH_TYPE;
if ((*CHAPUsername == TEXT('-')) || (*CHAPUsername == TEXT('*')))
{
LoginOptions->Username = NULL;
LoginOptions->UsernameLength = 0;
Status = ERROR_SUCCESS;
} else {
#ifdef UNICODE
LoginOptions->Username = NULL;
Status = DiscpUnicodeToAnsi(
CHAPUsername,
(LPSTR *)&LoginOptions->Username,
0);
#else
LoginOptions->Username = CHAPUsername;
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
LoginOptions->UsernameLength = (ULONG)strlen((LPCSTR)LoginOptions->Username);
}
}
if (Status == ERROR_SUCCESS)
{
if ((*CHAPPassword == TEXT('-')) || *CHAPPassword == TEXT('*'))
{
LoginOptions->Password = NULL;
LoginOptions->PasswordLength = 0;
Status = ERROR_SUCCESS;
} else {
Secret = CHAPPassword;
if ((Secret[0] == TEXT('0')) &&
((Secret[1] == TEXT('X')) ||
(Secret[1] == TEXT('x'))))
{
Status = ParseHexString(Secret+2,
&LoginOptions->Password,
&LoginOptions->PasswordLength);
} else {
#ifdef UNICODE
LoginOptions->Password = NULL;
Status = DiscpUnicodeToAnsi(
CHAPPassword,
(LPSTR *)&LoginOptions->Password,
0);
#else
LoginOptions->Password = CHAPPassword;
Status = ERROR_SUCCESS;
#endif
if (Status == ERROR_SUCCESS)
{
LoginOptions->PasswordLength = (ULONG)strlen((LPCSTR)LoginOptions->Password);
}
}
}
if (Status == ERROR_SUCCESS)
{
*LoginOptionsPtr = LoginOptions;
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return(Status);
}
ISDSC_STATUS QLoginTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli QLoginTarget <TargetName> [CHAP Username] [CHAP Password]\n");
{
ISDSC_STATUS Status;
PTCHAR TargetName, CHAPUsername, CHAPPassword;
PISCSI_LOGIN_OPTIONS LoginOptions;
ISCSI_UNIQUE_SESSION_ID SessionId;
ISCSI_UNIQUE_SESSION_ID ConnectionId;
if ((ArgC != 3) && (ArgC != 5))
{
Usage(33);
return(ERROR_SUCCESS);
}
TargetName = ArgV[2];
if (ArgC == 5)
{
CHAPUsername = ArgV[3];
CHAPPassword = ArgV[4];
Status = BuildLoginOptionsForCHAP(CHAPUsername,
CHAPPassword,
&LoginOptions);
} else {
LoginOptions = NULL;
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS)
{
Status = LoginIScsiTarget(TargetName,
FALSE, // IsInformationalSession
NULL, // InitiatorInstance,
ISCSI_ANY_INITIATOR_PORT,
NULL, // TargetPortal
0, // SecurityFlags,
NULL, // Mappings,
LoginOptions,
0, // KeySize,
NULL, // Key
FALSE, // IsPersistent,
&SessionId,
&ConnectionId);
if (Status == ERROR_SUCCESS)
{
printf("Session Id is 0x%I64x-0x%I64x\n",
SessionId.AdapterUnique,
SessionId.AdapterSpecific);
printf("Connection Id is 0x%I64x-0x%I64x\n",
ConnectionId.AdapterUnique,
ConnectionId.AdapterSpecific);
}
}
if (LoginOptions != NULL)
{
#ifdef UNICODE
if (LoginOptions->Username != NULL)
{
Free(LoginOptions->Username);
}
if (LoginOptions->Password != NULL)
{
Free(LoginOptions->Password);
}
#endif
Free(LoginOptions);
}
return(Status);
}
ISDSC_STATUS QAddTarget(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli QAddTarget <TargetName> <TargetPortalAddress>\n");
{
ISDSC_STATUS Status;
ISCSI_TARGET_PORTAL_GROUP PortalGroup;
PTCHAR TargetName, TargetPortalAddress;
HRESULT hr;
if (ArgC != 4)
{
Usage(34);
return(ERROR_SUCCESS);
}
TargetName = ArgV[2];
if (*ArgV[3] != TEXT('*'))
{
TargetPortalAddress = ArgV[3];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
PortalGroup.Count = 1;
*PortalGroup.Portals[0].SymbolicName = 0;
hr = StringCchCopy(PortalGroup.Portals[0].Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
PortalGroup.Portals[0].Socket = 3260;
} else {
PortalGroup.Count = 0;
*PortalGroup.Portals[0].Address = 0;
}
Status = AddIScsiStaticTarget(TargetName,
NULL, // TargetAlias,
0, // TargetFlags
TRUE, // Persist
NULL, // Mappings
NULL, // LoginOptions
&PortalGroup);
return(Status);
}
ISDSC_STATUS QAddTargetPortal(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli QAddTargetPortal <TargetPortalAddress>
// printf(" [CHAP Username] [CHAP Password]\n"
{
ISDSC_STATUS Status;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR TargetPortalAddress;
PTCHAR CHAPUsername, CHAPPassword;
PISCSI_LOGIN_OPTIONS LoginOptions;
HRESULT hr;
if ((ArgC != 3) && (ArgC != 5))
{
Usage(35);
return(ERROR_SUCCESS);
}
TargetPortalAddress = ArgV[2];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Address[MAX_ISCSI_PORTAL_ADDRESS_LEN-1] = 0;
TargetPortal.Socket = 3260;
*TargetPortal.SymbolicName = 0;
if (ArgC == 5)
{
CHAPUsername = ArgV[3];
CHAPPassword = ArgV[4];
Status = BuildLoginOptionsForCHAP(CHAPUsername,
CHAPPassword,
&LoginOptions);
} else {
LoginOptions = NULL;
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS)
{
Status = AddIScsiSendTargetPortal(NULL, // InitiatorInstance,
ISCSI_ANY_INITIATOR_PORT,
LoginOptions,
0, // SecurityFlags,
&TargetPortal);
}
if (LoginOptions != NULL)
{
#ifdef UNICODE
if (LoginOptions->Username != NULL)
{
Free(LoginOptions->Username);
}
if (LoginOptions->Password != NULL)
{
Free(LoginOptions->Password);
}
#endif
Free(LoginOptions);
}
return(Status);
}
ISDSC_STATUS QAddConnection(
int ArgC,
__in_ecount(ArgC) PTCHAR *ArgV
)
// printf("iscsicli QAddConnection <SessionId> <Initiator Instance>\n");
// printf(" <Target Portal Address>
// printf(" [CHAP Username] [CHAP Password]\n");
{
ISDSC_STATUS Status;
ISCSI_UNIQUE_SESSION_ID SessionId;
ISCSI_TARGET_PORTAL TargetPortal;
PTCHAR TargetPortalAddress;
ISCSI_UNIQUE_CONNECTION_ID ConnectionId;
PTCHAR InitiatorName;
PISCSI_LOGIN_OPTIONS LoginOptions;
PTCHAR CHAPUsername, CHAPPassword;
HRESULT hr;
if ((ArgC != 5) && (ArgC != 7))
{
Usage(36);
return(ERROR_SUCCESS);
}
if (! StringToSessionId(ArgV[2], &SessionId))
{
Usage(36);
return(ERROR_SUCCESS);
}
InitiatorName = ArgV[3];
if (*ArgV[4] != TEXT('*'))
{
TargetPortalAddress = ArgV[4];
if (_tcslen(TargetPortalAddress) > (MAX_ISCSI_PORTAL_ADDRESS_LEN-1))
{
return(ERROR_INVALID_PARAMETER);
}
hr = StringCchCopy(TargetPortal.Address,
MAX_ISCSI_PORTAL_ADDRESS_LEN,
TargetPortalAddress);
TargetPortal.Socket = 3260;
*TargetPortal.SymbolicName = 0;
} else {
TargetPortalAddress = TEXT("");
}
if (ArgC == 7)
{
CHAPUsername = ArgV[5];
CHAPPassword = ArgV[6];
Status = BuildLoginOptionsForCHAP(CHAPUsername,
CHAPPassword,
&LoginOptions);
} else {
LoginOptions = NULL;
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS)
{
Status = AddIScsiConnection(&SessionId,
InitiatorName,
ISCSI_ANY_INITIATOR_PORT,
*TargetPortalAddress == 0 ?
NULL : &TargetPortal,
0, // SecurityFlags,
LoginOptions,
0, // KeySize,
NULL, // Key
&ConnectionId);
if (Status == ERROR_SUCCESS)
{
printf("Connection Id is 0x%I64x-0x%I64x\n",
ConnectionId.AdapterUnique,
ConnectionId.AdapterSpecific);
}
}
if (LoginOptions != NULL)
{
#ifdef UNICODE
if (LoginOptions->Username != NULL)
{
Free(LoginOptions->Username);
}
if (LoginOptions->Password != NULL)
{
Free(LoginOptions->Password);
}
#endif
Free(LoginOptions);
}
return(Status);
}
VOID __cdecl PrintErrorMessage(
DWORD dwError,
__in_opt LPTSTR szFmt,
...
)
{
LPTSTR szT;
va_list arglist;
LPTSTR szErrMessage = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwError, 0/*LANG_USER_DEFAULT*/, (LPTSTR)&szErrMessage, 0, NULL);
if(szFmt && szErrMessage)
{
for(szT = szErrMessage; *szT; szT++)
{
if(*szT == '\r' || *szT == '\n')
*szT = 0;
}
}
#ifdef UNICODE
printf("Error 0x%08lx. %ws", dwError, szErrMessage ? szErrMessage : L"");
#else
printf("Error 0x%08lx. %s", dwError, szErrMessage ? szErrMessage : "");
#endif
if(szFmt)
{
va_start(arglist, szFmt);
#ifdef UNICODE
vwprintf(szFmt, arglist);
#else
vprintf(szFmt, arglist);
#endif
va_end(arglist);
}
if(szErrMessage)
LocalFree((HLOCAL)szErrMessage);
}
ISDSC_STATUS PerformCommandLine(
#ifdef UNICODE
__in PTCHAR CommandLine
#else
int argc,
__in_ecount(argc) char *argv[]
#endif
)
{
int ArgC;
PTCHAR *ArgV;
ISDSC_STATUS Status = ERROR_SUCCESS;
TCHAR Message[FORMAT_MESSAGE_MAX_WIDTH_MASK];
#ifdef UNICODE
ArgV = CommandLineToArgvW(CommandLine, &ArgC);
#else
ArgC = argc;
ArgV = argv;
#endif
if (ArgV != NULL)
{
if (ArgC > 1)
{
// AddIScsiStaticTarget
if (_tcsicmp(ArgV[1], TEXT("AddTarget")) == 0)
{
Status = AddTarget(ArgC, ArgV);
// RemoveIScsiStaticTarget
} else if (_tcsicmp(ArgV[1], TEXT("RemoveTarget")) == 0) {
Status = RemoveTarget(ArgC, ArgV);
// AddIScsiSendTargetPortal
} else if (_tcsicmp(ArgV[1], TEXT("AddTargetPortal")) == 0) {
Status = AddTargetPortal(ArgC, ArgV);
// RemoveIScsiSendTargetPortal
} else if (_tcsicmp(ArgV[1], TEXT("RemoveTargetPortal")) == 0) {
Status = RemoveTargetPortal(ArgC,ArgV);
// RefreshIScsiSendTargetPortal
} else if (_tcsicmp(ArgV[1], TEXT("RefreshTargetPortal")) == 0) {
Status = RefreshTargetPortal(ArgC,ArgV);
// ReportIScsiSendTargetPortals
} else if (_tcsicmp(ArgV[1], TEXT("ListTargetPortals")) == 0) {
Status = ListTargetPortals(ArgC,ArgV);
// ReportTargets
} else if (_tcsicmp(ArgV[1], TEXT("ListTargets")) == 0) {
Status = ListTargets(ArgC,ArgV);
// GetTargetInformation
} else if (_tcsicmp(ArgV[1], TEXT("TargetInfo")) == 0) {
Status = TargetInfo(ArgC,ArgV);
// LoginTarget
} else if (_tcsicmp(ArgV[1], TEXT("LoginTarget")) == 0) {
Status = TryLoginToTarget(ArgC,ArgV);
// PersistentLoginTarget
} else if (_tcsicmp(ArgV[1], TEXT("PersistentLoginTarget")) == 0) {
Status = PersistentLoginTarget(ArgC,ArgV);
// RemovePersistentTarget
} else if (_tcsicmp(ArgV[1], TEXT("RemovePersistentTarget")) == 0) {
Status = RemovePersistentTarget(ArgC,ArgV);
// ListPersistentTarget
} else if (_tcsicmp(ArgV[1], TEXT("ListPersistentTargets")) == 0) {
Status = ListPersistentTarget(ArgC,ArgV);
// LogoutTarget
} else if (_tcsicmp(ArgV[1], TEXT("LogoutTarget")) == 0) {
Status = DoLogoutTarget(ArgC,ArgV);
// ReportInitiatorList
} else if (_tcsicmp(ArgV[1], TEXT("ListInitiators")) == 0) {
Status = DoReportInitiatorList(ArgC,ArgV);
// ReportActiveIScsiTargetMappings
} else if (_tcsicmp(ArgV[1], TEXT("ReportTargetMappings")) == 0) {
Status = DoReportActiveIScsiTargetMappings(ArgC,ArgV);
// AddConnection
} else if (_tcsicmp(ArgV[1], TEXT("AddConnection")) == 0) {
Status = DoAddConnection(ArgC,ArgV);
// RemoveConnection
} else if (_tcsicmp(ArgV[1], TEXT("RemoveConnection")) == 0) {
Status = DoRemoveConnection(ArgC,ArgV);
// SendScsiInquiry
} else if (_tcsicmp(ArgV[1], TEXT("ScsiInquiry")) == 0) {
Status = DoScsiInquiry(ArgC,ArgV);
// SendScsiReadCapacity
} else if (_tcsicmp(ArgV[1], TEXT("ReadCapacity")) == 0) {
Status = ReadCapacity(ArgC,ArgV);
// SendScsiReportLuns
} else if (_tcsicmp(ArgV[1], TEXT("ReportLUNs")) == 0) {
Status = ReportLUNs(ArgC,ArgV);
// AddiSNSServer
} else if (_tcsicmp(ArgV[1], TEXT("AddiSNSServer")) == 0) {
Status = AddiSNSServerX(ArgC,ArgV);
// RemoveiSNSServer
} else if (_tcsicmp(ArgV[1], TEXT("RemoveiSNSServer")) == 0) {
Status = RemoveiSNSServerX(ArgC,ArgV);
// ListiSNSServers
} else if (_tcsicmp(ArgV[1], TEXT("ListiSNSServers")) == 0) {
Status = ListiSNSServers(ArgC,ArgV);
// RefreshiSNSServer
} else if (_tcsicmp(ArgV[1], TEXT("RefreshiSNSServer")) == 0) {
Status = RefreshiSNSServer(ArgC,ArgV);
// TunnelAddr
} else if (_tcsicmp(ArgV[1], TEXT("TunnelAddr")) == 0) {
Status = TunnelAddress(ArgC,ArgV);
// GroupKey
} else if (_tcsicmp(ArgV[1], TEXT("GroupKey")) == 0) {
Status = GroupKey(ArgC,ArgV);
// PSKey
} else if (_tcsicmp(ArgV[1], TEXT("PSKey")) == 0) {
Status = PSKey(ArgC,ArgV);
// CHAPSecret
} else if (_tcsicmp(ArgV[1], TEXT("CHAPSecret")) == 0) {
Status = CHAPSecret(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("NodeName")) == 0) {
Status = NodeName(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("SessionList")) == 0) {
Status = SessionList(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("BindPersistentVolumes")) == 0) {
Status = BindPeristentVolumes(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("BindPersistentDevices")) == 0) {
Status = BindPeristentVolumes(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("AddPersistentDevice")) == 0) {
Status = AddPersistentVolume(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("RemovePersistentDevice")) == 0) {
Status = RemovePersistentVolume(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("ClearPersistentDevices")) == 0) {
Status = ClearPersistentVolumes(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("ReportPersistentDevices")) == 0) {
Status = ReportPersistentVolumes(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("GetPSKey")) == 0) {
Status = GetPSKey(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("QLoginTarget")) == 0) {
Status = QLoginTarget(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("QAddTarget")) == 0) {
Status = QAddTarget(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("QAddTargetPortal")) == 0) {
Status = QAddTargetPortal(ArgC,ArgV);
} else if (_tcsicmp(ArgV[1], TEXT("QAddConnection")) == 0) {
Status = QAddConnection(ArgC,ArgV);
} else {
Usage(0);
Status = ERROR_SUCCESS;
}
} else {
Usage(0);
Status = ERROR_SUCCESS;
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
#ifdef UNICODE
printf("%ws\n", GetiSCSIMessageText(Message,
FORMAT_MESSAGE_MAX_WIDTH_MASK,
Status));
#else
printf("%s\n", GetiSCSIMessageText(Message,
FORMAT_MESSAGE_MAX_WIDTH_MASK,
Status));
#endif
return(Status);
}
#define INPUT_BUFFER_SIZE 4096
TCHAR s[INPUT_BUFFER_SIZE];
TCHAR s1[INPUT_BUFFER_SIZE];
int _cdecl main(int argc, __in_ecount(argc) char *argv[])
{
ISDSC_STATUS Status;
#ifdef UNICODE
ULONG Len;
#endif
TCHAR m[MAX_PATH];
TCHAR NodeName[MAX_ISCSI_NAME_LEN+1];
ISCSI_VERSION_INFO iSCSIVer;
HRESULT hr;
WORD wVersionRequested;
WSADATA DiscpWsaData;
UNREFERENCED_PARAMETER(argv);
Status = GetIScsiVersionInformation(&iSCSIVer);
if (Status == ERROR_SUCCESS)
{
printf("Microsoft iSCSI Initiator Version %d.%d\n\n",
iSCSIVer.MajorVersion,
iSCSIVer.MinorVersion
);
}
wVersionRequested = MAKEWORD( 1, 1 );
Status = WSAStartup( wVersionRequested, &DiscpWsaData );
if (Status == ERROR_SUCCESS)
{
if (argc == 1)
{
#ifdef UNICODE
while (! feof(stdin))
{
Status = GetIScsiInitiatorNodeName(NodeName);
if (Status == ERROR_SUCCESS)
{
printf("[%ws] Enter command or ^C to exit\n", NodeName);
if (_fgetts(s, INPUT_BUFFER_SIZE, stdin) != NULL)
{
hr = StringCchCopy(s1,
INPUT_BUFFER_SIZE,
TEXT("iscsicli "));
hr = StringCchCat(s1,
INPUT_BUFFER_SIZE,
s);
Len = ((ULONG)_tcslen(s1)-1);
if (s1[Len] == 0xa)
{
s1[Len] = 0;
}
Status = PerformCommandLine(s1);
}
} else {
#ifdef UNICODE
printf("Error getting node name: %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#else
printf("Error getting node name: %s\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
#endif
break;
}
}
#else
Usage(0);
Status = GetIScsiInitiatorNodeName(NodeName);
if (Status == ERROR_SUCCESS)
{
printf("Running on node name %s\n", NodeName);
}
#endif
} else {
#ifdef UNICODE
Status = PerformCommandLine(GetCommandLineW());
#else
Status = PerformCommandLine(argc, argv);
#endif
}
WSACleanup();
} else {
printf("Error setting up Windows sockets: %ws\n",
GetiSCSIMessageText(m, MAX_PATH, Status));
}
return(Status);
}