//*************************************************************************** // // 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 #include #include #include #include #include #include #include "iscsierr.h" #include "iscsidsc.h" #include #include #include #include // // 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 \n"); printf(" \n"); printf("
\n"); printf(" \n"); printf(" \n"); printf(" \n"); printf(" ...\n"); printf("\n"); } if ((Code == 0) || (Code == 2)) { printf("iscsicli RemoveTarget \n"); printf("\n"); } if ((Code == 0) || (Code == 3)) { printf("iscsicli AddTargetPortal \n"); printf(" [HBA Name] [Port Number]\n"); printf(" \n"); printf("
\n"); printf(" \n"); printf(" \n"); printf("\n"); } if ((Code == 0) || (Code == 4)) { printf("iscsicli RemoveTargetPortal [HBA Name] [Port Number]\n"); printf("\n"); } if ((Code == 0) || (Code == 5)) { printf("iscsicli RefreshTargetPortal [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 [Discovery Mechanism]\n"); printf("\n"); } if ((Code == 0) || (Code == 9)) { printf("iscsicli LoginTarget \n"); printf(" \n"); printf(" \n"); printf("
\n"); printf(" \n"); printf(" \n"); printf(" \n"); printf(" ...\n"); printf("\n"); } if ((Code == 0) || (Code == 10)) { printf("iscsicli LogoutTarget \n"); printf("\n"); } if ((Code == 0) || (Code == 11)) { printf("iscsicli PersistentLoginTarget \n"); printf(" \n"); printf(" \n"); printf("
\n"); printf(" \n"); printf(" \n"); printf(" \n"); printf(" ...\n"); printf("\n"); } if ((Code == 0) || (Code == 12)) { printf("iscsicli ListPersistentTargets\n"); printf("\n"); } if ((Code == 0) || (Code == 13)) { printf("iscsicli RemovePersistentTarget \n"); printf(" \n"); printf(" \n"); printf(" \n"); printf("\n"); } if ((Code == 0) || (Code == 14)) { printf("iscsicli AddConnection \n"); printf(" \n"); printf(" \n"); printf("
\n"); printf(" \n"); printf(" \n"); printf("\n"); } if ((Code == 0) || (Code == 15)) { printf("iscsicli RemoveConnection \n"); printf("\n"); } if ((Code == 0) || (Code == 16)) { printf("iscsicli ScsiInquiry \n"); printf("\n"); } if ((Code == 0) || (Code == 17)) { printf("iscsicli ReadCapacity \n"); printf("\n"); } if ((Code == 0) || (Code == 18)) { printf("iscsicli ReportLUNs \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 \n"); printf("\n"); } if ((Code == 0) || (Code == 22)) { printf("iscsicli RemoveiSNSServer \n"); printf("\n"); } if ((Code == 0) || (Code == 23)) { printf("iscsicli RefreshiSNSServer \n"); printf("\n"); } if ((Code == 0) || (Code == 24)) { printf("iscsicli ListiSNSServers\n"); printf("\n"); } if ((Code == 0) || (Code == 25)) { printf("iscsicli NodeName \n"); printf("\n"); } if ((Code == 0) || (Code == 26)) { printf("iscsicli SessionList \n"); printf("\n"); } if ((Code == 0) || (Code == 27)) { printf("iscsicli CHAPSecret \n"); printf("\n"); } if ((Code == 0) || (Code == 28)) { printf("iscsicli TunnelAddr \n"); printf("\n"); } if ((Code == 0) || (Code == 29)) { printf("iscsicli GroupKey \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 \n"); printf("\n"); } if ((Code == 0) || (Code == 39)) { printf("iscsicli RemovePersistentDevice \n"); printf("\n"); } if ((Code == 0) || (Code == 40)) { printf("iscsicli ClearPersistentDevices\n"); printf("\n"); } if ((Code == 0) || (Code == 42)) { printf("iscsicli GetPSKey \n"); printf("\n"); } if ((Code == 0) || (Code == 30)) { printf("iscsicli PSKey \n"); printf("\n"); } if (Code == 0) { printf("Quick Commands\n\n"); } if ((Code == 0) || (Code == 33)) { printf("iscsicli QLoginTarget [CHAP Username] [CHAP Password]\n"); printf("\n"); } if ((Code == 0) || (Code == 34)) { printf("iscsicli QAddTarget \n"); printf("\n"); } if ((Code == 0) || (Code == 35)) { printf("iscsicli QAddTargetPortal \n"); printf(" [CHAP Username] [CHAP Password]\n"); printf("\n"); } if ((Code == 0) || (Code == 36)) { printf("iscsicli QAddConnection \n"); printf(" \n"); printf(" [CHAP Username] [CHAP Password]\n"); printf("\n"); } if ((Code == 0) || (Code == 1) || (Code == 9) || (Code == 11)) { printf("Target Mappings:\n"); printf(" is the LUN value the target uses to expose the LUN.\n"); printf(" It must be in the form 0x0123456789abcdef\n"); printf(" is the bus number the OS should use to surface the LUN\n"); printf(" is the target number the OS should use to surface the LUN\n"); printf(" 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 : \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 { 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 { 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 { 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 \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 \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 { 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 // \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 // { 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 { 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 { 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 { 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 { 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"", TargetPortalAddress ? TargetPortal.Address : L"", TargetPortalAddress ? TargetPortal.Socket : 0 ); #else printf("LoginTarget to %s on %s to %s/%d\n", TargetName, InitiatorInstance ? InitiatorInstance : "", TargetPortalAddress ? TargetPortal.Address : "", 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 // // //
// // // // // ... // { ISDSC_STATUS Status; Status = DoLoginToTarget(ArgC, ArgV, FALSE); return(Status); } ISDSC_STATUS PersistentLoginTarget( int ArgC, __in_ecount(ArgC) PTCHAR *ArgV ) // iscsicli PersistentLoginTarget // // //
// // // // // ... // { ISDSC_STATUS Status; Status = DoLoginToTarget(ArgC, ArgV, TRUE); return(Status); } ISDSC_STATUS RemovePersistentTarget( int ArgC, __in_ecount(ArgC) PTCHAR *ArgV ) // printf("iscsicli RemovePersistentTarget \n" // printf(" \n"); // printf(" \n"); // printf(" \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 : \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 [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("")); Status = GetTargetInfo(ArgV[2], DiscoveryMechanism, DiscoveryMechanisms, &Size, &Buffer); if (Status == ERROR_SUCCESS) { if (Size > 0) { PrintStringList(" Discovery Mechanisms :", " ", Buffer, Size); } else { printf(" Discovery Mechanisms: \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 : \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 : \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 // // //
// // // { 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 \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 { 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 // [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 : \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 // [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 // [HBA Name] [PortNumber] // printf(" \n"); // printf("
\n"); // printf(" \n"); // printf(" // \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 { 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 // //
// // // // // ... { 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 { 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 { 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 { 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 [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 \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 // 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 \n"); // printf(" // 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); }