diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/iscsi/src/client | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'storage/iscsi/src/client')
| -rw-r--r-- | storage/iscsi/src/client/wmisample.c | 7990 |
1 files changed, 7990 insertions, 0 deletions
diff --git a/storage/iscsi/src/client/wmisample.c b/storage/iscsi/src/client/wmisample.c new file mode 100644 index 00000000..aff10be5 --- /dev/null +++ b/storage/iscsi/src/client/wmisample.c @@ -0,0 +1,7990 @@ +/*++ + +Copyright (C) Microsoft Corporation, 2000 + +Module Name: + + wmi.c + +Abstract: + + This file contains WMI routines for iSCSI miniport driver. + +Environment: + + kernel mode only + +--*/ + + +UCHAR iScsiQuerySecurityCapabilities( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferAvail, + PUCHAR Buffer, + PULONG InstanceLength, + PULONG SizeNeeded + ); + +UCHAR iScsiQueryDiscoveryConfig( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferAvail, + PUCHAR Buffer, + PULONG InstanceLength, + PULONG SizeNeeded + ); + +UCHAR iScsiAdvanceString( + OUT PWCHAR *String, + OUT PUSHORT StringLen, + IN OUT PUCHAR *Buffer, + IN OUT PULONG BufferSize + ); + +UCHAR iScsiSetDiscoveryConfig( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferSize, + PUCHAR Buffer + ); + +UCHAR iScsiAddPortalGroup( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN ULONG PortalCount + ); + +VOID iScsiCopyUTF8ToCounted( + PWCHAR p, + PUTF8CHAR UTF8, + ULONG UTF8Len + ); + +UCHAR iScsiAddPortalToGroup( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN ULONG Address, + IN PUTF8CHAR SymbolicName, + IN USHORT Socket, + IN ULONG SecurityBitmap, + IN ULONG KeySize, + IN PUCHAR Key + ); + +UCHAR iScsiAddDiscoveredTarget( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN PUTF8CHAR Name, + IN PUTF8CHAR Alias, + IN PUTF8CHAR DDName, + IN ULONG DDID, + IN ULONG PortalGroupCount + ); + +UCHAR iScsiReportDiscoveredTargets2( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferSize, + PULONG SizeNeeded, + PUCHAR Buffer + ); + +UCHAR +iSpReadTCPConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PUCHAR Buffer + ); + +UCHAR +iSpReadNICConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PUCHAR Buffer + ); + +UCHAR +iSpReadNICPerfData( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PUCHAR Buffer + ); + +UCHAR +iSpSetTCPConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN ULONG BufferSize, + IN PUCHAR Buffer + ); + +UCHAR +iScsiSetWmiDataBlock( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT DispatchConiScsiQueryWmiDataBlocktext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG BufferSize, + IN PUCHAR Buffer + ); + + +GUID iSCSI_Operations_GUID = MSiSCSI_OperationsGuid; +GUID iSCSI_HBAInformation_GUID = MSiSCSI_HBAInformationGuid; +GUID iScsiInitiatorInstanceStatisticsGuid = MSiSCSI_InitiatorInstanceStatisticsGuid; +GUID iScsiInitiatorInstanceFailureEventGuid = MSiSCSI_InitiatorInstanceFailureEventGuid; +GUID iScsiConnectStatisticsGuid = MSiSCSI_ConnectionStatisticsGuid; +GUID iScsiSessionStatisticsGuid = MSiSCSI_SessionStatisticsGuid; +GUID iScsi_InitiatorSessionInfo_GUID = MSiSCSI_InitiatorSessionInfoGuid; +GUID iScsi_InitiatorLoginStatistics_GUID = MSiSCSI_InitiatorLoginStatisticsGuid; +GUID iScsiInitiatorNodeFailureEventGuid = MSiSCSI_InitiatorInstanceFailureEventGuid; +GUID iScsiAdapterEventGuid = MSiSCSI_AdapterEventGuid; +GUID iScsiPortalInfoClassGuid = MSiSCSI_PortalInfoClassGuid; +GUID iScsiTargetMappingClassGuid = MSiSCSI_TargetMappingsGuid; +GUID iScsiPersistentLoginsClassGuid = MSiSCSI_PersistentLoginsGuid; +GUID iScsiLBOperationsGuid = MSiSCSI_LB_OperationsGuid; +GUID iScsiQueryLBPolicyGuid = MSiSCSI_QueryLBPolicyGuid; +GUID iSCSIEventlogGuid = MSiSCSI_EventlogGuid; +GUID iSCSIRedirectPortalGuid = MSiSCSI_RedirectPortalInfoClassGuid; +GUID iSCSIReqProcTimeGuid = MSiSCSI_RequestTimeStatisticsGuid; +GUID iSCSIBootInfoGuid = MSiSCSI_BootInformationGuid; + +GUID iScsiDiscoveryConfigGuid = MSiSCSI_DiscoveryConfigGuid; +GUID iSCSI_DiscoveryOperationsGuid = MSiSCSI_DiscoveryOperationsGuid; +GUID iSCSI_SecurityCapabilitiesGuid = MSiSCSI_SecurityCapabilitiesGuid; +GUID iSCSI_SecurityConfigOperationsGuid = MSiSCSI_SecurityConfigOperationsGuid; +GUID MSiScsiTCPConfigGuid = MSiSCSI_TCPIPConfigGuid; +GUID MSiScsiNICConfigGuid = MSiSCSI_NICConfigGuid; +GUID MSiScsiNICPerfGuid = MSiSCSI_NICPerformanceGuid; +GUID MSiSCSIManagementOperationsGuid= MSiSCSI_ManagementOperationsGuid; + +// +// This GUID will be replaced with the GUID for WMI Tracing in the port driver +// +GUID iSCSIDummyGuid = { 0,0,0, { 0,0,0,0,0,0,0,0 } }; + +// +// The index numbers should correspond to the offset in +// iScsiWmiGuidList array given below. +// +#define iSCSI_Operations_GUID_Index 0 +#define iSCSI_HBAInformation_GUID_Index 1 +#define iScsi_InitiatorInstanceStatistics_GUID_INDEX 2 +#define iScsi_InitiatorInstanceFailureEvent_GUID_INDEX 3 +#define iScsi_ConnectStatistics_GUID_INDEX 4 +#define iScsi_SessionStatistics_GUID_INDEX 5 +#define iScsi_InitiatorSessionInfo_GUID_INDEX 6 +#define iScsi_InitiatorLoginStatistics_GUID_INDEX 7 +#define iScsi_InitiatorNodeFailureEvent_GUID_INDEX 8 +#define iScsi_AdapterEvent_GUID_Index 9 +#define iScsi_PortalInfoClass_GUID_Index 10 +#define iScsi_TargetMapping_GUID_Index 11 +#define iScsi_PersistentLogin_GUID_Index 12 +#define iScsi_LB_Operations_GUID_Index 13 +#define iScsi_Query_LB_Policy_GUID_Index 14 +#define iScsi_Eventlog_GUID_Index 15 +#define iScsi_Redirect_Portal_GUID_Index 16 +#define iScsi_RequestProcessingTime_GUID_Index 17 +#define iScsi_BootInfo_GUID_Index 18 + +#define iScsi_MAX_GUID_INDEX iScsi_BootInfo_GUID_Index + +#define iScsiDiscoveryConfigGuid_INDEX iScsi_MAX_GUID_INDEX + 1 +#define iSCSI_DiscoveryOperationsGuid_INDEX iScsi_MAX_GUID_INDEX + 2 +#define iSCSI_SecurityCapabilitiesGuid_INDEX iScsi_MAX_GUID_INDEX + 3 +#define iSCSI_SecurityConfigOperationsGuid_INDEX iScsi_MAX_GUID_INDEX + 4 +#define iScsi_TCPConfig_GUID_Index iScsi_MAX_GUID_INDEX + 5 +#define iScsi_NICConfig_GUID_Index iScsi_MAX_GUID_INDEX + 6 +#define iScsi_NICPerf_GUID_Index iScsi_MAX_GUID_INDEX + 7 +#define iScsi_ManagementOperation_GUID_Index iScsi_MAX_GUID_INDEX + 8 + +// +// GUID List and number of GUIDs in the list +// +SCSIWMIGUIDREGINFO iScsiWmiGuidList[] = +{ + { + &iSCSI_Operations_GUID, + 1, + 0 + }, + + { + &iSCSI_HBAInformation_GUID, + 1, + 0 + }, + + { + &iScsiInitiatorInstanceStatisticsGuid, + 1, + 0 + }, + + { + &iScsiInitiatorInstanceFailureEventGuid, + 1, + WMIREG_FLAG_EVENT_ONLY_GUID + }, + + { + &iScsiConnectStatisticsGuid, + 0xffffffff, //dynamic instance names + 0 + }, + + { + &iScsiSessionStatisticsGuid, + 0xffffffff, //dynamic instance names + 0 + }, + + { + &iScsi_InitiatorSessionInfo_GUID, + 1, + 0 + }, + + { + &iScsi_InitiatorLoginStatistics_GUID, + 1, + 0 + }, + + { + &iScsiInitiatorNodeFailureEventGuid, + 1, + WMIREG_FLAG_EVENT_ONLY_GUID + }, + + { + &iScsiAdapterEventGuid, + 1, + WMIREG_FLAG_EVENT_ONLY_GUID + }, + + { + &iScsiPortalInfoClassGuid, + 1, + 0 + }, + + { + &iScsiTargetMappingClassGuid, + 1, + 0 + }, + + { + &iScsiPersistentLoginsClassGuid, + 1, + 0 + }, + + { + &iScsiLBOperationsGuid, + 1, + 0 + }, + + { + &iScsiQueryLBPolicyGuid, + 1, + 0 + }, + + { + &iSCSIEventlogGuid, + 1, + 0 + }, + + { + &iSCSIRedirectPortalGuid, + 1, + 0 + }, + + { + &iSCSIReqProcTimeGuid, + 0xffffffff, //dynamic instance names + 0 + }, + + { + &iSCSIBootInfoGuid, + 1, + 0 + }, + + { + &iScsiDiscoveryConfigGuid, + 1, + 0 + }, + + { + &iSCSI_DiscoveryOperationsGuid, + 1, + 0 + }, + + { + &iSCSI_SecurityCapabilitiesGuid, + 1, + 0 + }, + + { + &iSCSI_SecurityConfigOperationsGuid, + 1, + 0 + }, + + { + &MSiScsiTCPConfigGuid, + 1, + 0 + }, + + { + &MSiScsiNICConfigGuid, + 1, + 0 + }, + + { + &MSiScsiNICPerfGuid, + 1, + 0 + }, + + { + &MSiSCSIManagementOperationsGuid, + 1, + 0 + }, + +}; + +#define iScsiWmiGuidCount (sizeof(iScsiWmiGuidList) / sizeof(SCSIWMIGUIDREGINFO)) + +// +// WMI Guid list for the PDO +// +GUID iSCSI_LUNMappingInformationGuid = MSiSCSI_LUNMappingInformationGuid; + +#define MSiSCSI_LUNMappingInformation_Index 0 + +SCSIWMIGUIDREGINFO iScsiPDOWmiGuidList[] = +{ + { + &iSCSI_LUNMappingInformationGuid, + 1, + 0 + } +}; + +#define iScsiPDOWmiGuidCount (sizeof(iScsiPDOWmiGuidList) / sizeof(SCSIWMIGUIDREGINFO)) + +VOID +iScsiWmiInitializeContext( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension + ) +/*+++ + +Routine Description: + + This routine will initialize the wmilib context structure with the + guid list and the pointers to the wmilib callback functions. + +Arguments: + + AdapterExtension - Adpater extension + +Return Value: + + None. + +--*/ +{ + PSCSI_WMILIB_CONTEXT wmiLibContext; + + + // + // Initialize the wmilib context for the adapter + // + wmiLibContext = &(AdapterExtension->WmiLibContext); + + wmiLibContext->GuidList = iScsiWmiGuidList; + wmiLibContext->GuidCount = iScsiWmiGuidCount; + + // + // Set pointers to WMI callback routines + // + wmiLibContext->QueryWmiRegInfo = iScsiQueryWmiRegInfo; + wmiLibContext->QueryWmiDataBlock = iScsiQueryWmiDataBlock; + wmiLibContext->ExecuteWmiMethod = iScsiExecuteWmiMethod; + wmiLibContext->WmiFunctionControl = NULL; + wmiLibContext->SetWmiDataItem = NULL; + + + wmiLibContext->SetWmiDataBlock = iScsiSetWmiDataBlock; + + // + // Initialize discovery config + // + AdapterExtension->DiscoveryConfigFlags = (DISCOVERY_CONFIG_DO_DISCOVERY | + DISCOVERY_CONFIG_FIND_SNS_AUTOMATICALLY); + AdapterExtension->SNSServer[0] = 0; + + + // + // Initialize the wmilib context for the PDO + // + wmiLibContext = &(AdapterExtension->PDOWmiLibContext); + + wmiLibContext->GuidList = iScsiPDOWmiGuidList; + wmiLibContext->GuidCount = iScsiPDOWmiGuidCount; + + // + // Set pointers to WMI callback routines + // + wmiLibContext->QueryWmiRegInfo = iScsiQueryWmiRegInfo; + wmiLibContext->QueryWmiDataBlock = iScsiPDOQueryWmiDataBlock; + wmiLibContext->ExecuteWmiMethod = NULL; + wmiLibContext->WmiFunctionControl = NULL; + wmiLibContext->SetWmiDataItem = NULL; + wmiLibContext->SetWmiDataBlock = NULL; + + return; +} + +BOOLEAN +iScsiWmiSrb( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN OUT PSCSI_WMI_REQUEST_BLOCK Srb + ) +/*++ + +Routine Description: + + Called from StartIo routine to process an SRB_FUNCTION_WMI request. + Main entry point for all WMI routines. + +Arguments: + + AdapterExtension - ISCSI miniport driver's Adapter extension. + + Srb - IO request packet. + +Return Value: + + Always TRUE. + +--*/ +{ + PSCSIWMI_REQUEST_CONTEXT requestContext; + PISCSI_SRB_EXTENSION srbExtension; + BOOLEAN pending; + BOOLEAN completeRequest = TRUE; + BOOLEAN adapterRequest; + + + // + // Validate our assumptions. + // + NT_ASSERT(Srb->Function == SRB_FUNCTION_WMI); + NT_ASSERT(Srb->Length == sizeof(SCSI_WMI_REQUEST_BLOCK)); + + srbExtension = (PISCSI_SRB_EXTENSION) Srb->SrbExtension; + + requestContext = &(srbExtension->WmiRequestContext); + + // + // Save the pointer to the SRB in UserContext + // of SCSIWMI_REQUEST_CONTEXT + // + requestContext->UserContext = Srb; + + // + // Check if the WMI SRB is targetted for + // the iScsi adapter or one of the devices + // + adapterRequest = (Srb->WMIFlags & SRB_WMI_FLAGS_ADAPTER_REQUEST) == SRB_WMI_FLAGS_ADAPTER_REQUEST; + + // + // Process the incoming WMI request. + // + DebugPrint((iScsiPrtDebugTrace, + "Entering iScsiWmiSrb\n")); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "Entering iScsiWmiSrb\n"); + + pending = ScsiPortWmiDispatchFunction(adapterRequest ? + &AdapterExtension->WmiLibContext : + &AdapterExtension->PDOWmiLibContext, + Srb->WMISubFunction, + AdapterExtension, + requestContext, + Srb->DataPath, + Srb->DataTransferLength, + Srb->DataBuffer); + if (pending == FALSE) { + + // + // We can do this since we assume it is done synchronously + // + Srb->DataTransferLength = ScsiPortWmiGetReturnSize(requestContext);; + + // + // Adapter ready for next request. + // + Srb->SrbStatus = ScsiPortWmiGetReturnStatus(requestContext); + + } else { + completeRequest = FALSE; + } + + if (completeRequest == TRUE) { + ScsiPortNotification(RequestComplete, AdapterExtension, Srb); + } + + return TRUE; +} + +UCHAR +iScsiQueryWmiRegInfo( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT RequestContext, + _Out_ PWCHAR *MofResourceName + ) +/*+++ + +Routine Description: + + This routine returns MofResourceName for this driver. + +--*/ +{ + *MofResourceName = iScsiWmi_MofResourceName; + + return SRB_STATUS_SUCCESS; +} + +BOOLEAN +iScsiQueryWmiDataBlock( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG InstanceCount, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer + ) +/*+++ + +Routine Description : + + Called to query WMI Data blocks + +--*/ +{ + PISCSI_ADAPTER_EXTENSION adapterExtension; + PSCSI_WMI_REQUEST_BLOCK srb; + UCHAR status; + ULONG sizeNeeded = 0; + NTSTATUS ntStatus; + + + adapterExtension = (PISCSI_ADAPTER_EXTENSION) Context; + srb = (PSCSI_WMI_REQUEST_BLOCK) DispatchContext->UserContext; + + switch (GuidIndex) { + case iSCSI_Operations_GUID_Index: + case iScsi_LB_Operations_GUID_Index: { + + // + // Even though this class only has methods, we need to + // respond to any queries for it since WMI expects that + // there is an actual instance of the class on which to + // execute the method + // + + sizeNeeded = sizeof(ULONG); + if (BufferAvail >= sizeNeeded) { + *InstanceLengthArray = sizeNeeded; + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + case iSCSI_HBAInformation_GUID_Index: { + + PMSiSCSI_HBAInformation iScsiHBAInformation; + + sizeNeeded = sizeof(MSiSCSI_HBAInformation); + if (BufferAvail >= sizeNeeded) { + + *InstanceLengthArray = sizeNeeded; + + iScsiHBAInformation = (PMSiSCSI_HBAInformation) Buffer; + + ntStatus = iSpBuildHBAInformationBuffer(adapterExtension, iScsiHBAInformation); + + status = NT_SUCCESS(ntStatus) ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR; + + } else { + + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + case iScsi_InitiatorInstanceStatistics_GUID_INDEX: { + + sizeNeeded = sizeof(MSiSCSI_InitiatorInstanceStatistics); + + if (BufferAvail >= sizeNeeded) { + + status = iSpReadInitiatorInstanceStatistics(adapterExtension, + Buffer); + + if (status != SRB_STATUS_ERROR) { + *InstanceLengthArray = sizeNeeded; + + status = SRB_STATUS_SUCCESS; + } + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + case iScsi_ConnectStatistics_GUID_INDEX: { + + status = iSpBuildConnectionStatistics(adapterExtension, + DispatchContext, + GuidIndex, + InstanceIndex, + InstanceCount, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + break; + } + + case iScsi_RequestProcessingTime_GUID_Index: { + + status = iSpBuildRequestTimeStatistics(adapterExtension, + DispatchContext, + GuidIndex, + InstanceIndex, + InstanceCount, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + break; + } + + case iScsi_SessionStatistics_GUID_INDEX: { + + + status = iSpBuildSessionStatistics(adapterExtension, + DispatchContext, + GuidIndex, + InstanceIndex, + InstanceCount, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + break; + } + + case iScsi_InitiatorLoginStatistics_GUID_INDEX: { + PWMI_CONNECTION_LIST connectionList; + ULONG numberOfSessions; + ULONG numberOfConnections; + + sizeNeeded = sizeof(MSiSCSI_InitiatorLoginStatistics); + if (BufferAvail >= sizeNeeded) + { + RtlZeroMemory(Buffer, sizeNeeded); + + connectionList = iSpGetConnectionList(adapterExtension, + &numberOfSessions, + &numberOfConnections); + + if (connectionList != NULL) + { + status = iSpReadInitiatorLoginStatistics(adapterExtension, + connectionList, + numberOfSessions, + Buffer); + + *InstanceLengthArray = sizeNeeded; + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + } else { + status = SRB_STATUS_ERROR; + } + + + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + break; + } + + case iScsi_InitiatorSessionInfo_GUID_INDEX: { + + status = iSpBuildInitiatorSessionInfo(adapterExtension, + DispatchContext, + BufferAvail, + Buffer, + &sizeNeeded); + + *InstanceLengthArray = sizeNeeded; + + break; + + } + + case iScsi_PortalInfoClass_GUID_Index: { + status = iSpBuildPortalInfo(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + break; + } + + case iScsi_TargetMapping_GUID_Index: { + + status = iSpBuildTargetMapping(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + break; + } + + case iScsi_PersistentLogin_GUID_Index: { + + status = iSpBuildPersistentLoginInfo(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + *InstanceLengthArray = sizeNeeded; + + break; + } + + case iScsi_Query_LB_Policy_GUID_Index: { + + status = iSpQueryLBPolicy(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + *InstanceLengthArray = sizeNeeded; + + break; + } + + case iScsi_Redirect_Portal_GUID_Index: { + + status = iSpBuildRedirectTargetInfo(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + *InstanceLengthArray = sizeNeeded; + + break; + } + + case iScsi_BootInfo_GUID_Index: { + + status = iSpBuildBootInfo(adapterExtension, + InstanceLengthArray, + BufferAvail, + Buffer, + &sizeNeeded); + + *InstanceLengthArray = sizeNeeded; + + break; + } + + + + case iSCSI_SecurityCapabilitiesGuid_INDEX: + { + status = iScsiQuerySecurityCapabilities(adapterExtension, + BufferAvail, + Buffer, + InstanceLengthArray, + &sizeNeeded); + break; + } + + case iScsiDiscoveryConfigGuid_INDEX: + { + status = iScsiQueryDiscoveryConfig(adapterExtension, + BufferAvail, + Buffer, + InstanceLengthArray, + &sizeNeeded); + break; + } + + case iSCSI_SecurityConfigOperationsGuid_INDEX: + case iSCSI_DiscoveryOperationsGuid_INDEX: + case iScsi_ManagementOperation_GUID_Index: + { + // + // Operations only has methods, but we need to support the + // query since WMI needs to be able to query before + // executing a method + // + sizeNeeded = sizeof(ULONG); + if (BufferAvail >= sizeNeeded) + { + *InstanceLengthArray = sizeNeeded; + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + break; + } + + case iScsi_TCPConfig_GUID_Index: + { + sizeNeeded = sizeof(MSiSCSI_TCPIPConfig); + if (BufferAvail >= sizeNeeded) { + *InstanceLengthArray = sizeNeeded; + status = iSpReadTCPConfigInfo(adapterExtension, Buffer); + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + case iScsi_NICConfig_GUID_Index: + { + sizeNeeded = sizeof(MSiSCSI_NICConfig); + + if (BufferAvail >= sizeNeeded) + { + *InstanceLengthArray = sizeNeeded; + status = iSpReadNICConfigInfo(adapterExtension, Buffer); + + } else { + + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + case iScsi_NICPerf_GUID_Index: + { + sizeNeeded = sizeof(MSiSCSI_NICPerformance); + + if (BufferAvail >= sizeNeeded) + { + *InstanceLengthArray = sizeNeeded; + status = iSpReadNICPerfData(adapterExtension, Buffer); + + } else { + + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + default: { + status = SRB_STATUS_ERROR; + break; + } + + } + + iSpCompleteWmiRequest(adapterExtension, srb, DispatchContext, status, sizeNeeded); + + // + // return SRB_STATUS_PENDING since the request has either already been + // completed in iSpCompleteWmiRequest or the status is really + // SRB_STATUS_PENDING. This implies that the iScsiWmiSrb routine + // may not touch the srb since it is already completed. + // + return SRB_STATUS_PENDING; + +} + +VOID +iScsiBuildLUNMapping( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + PMSiSCSI_LUNMappingInformation Mapping, + PSCSI_WMI_REQUEST_BLOCK Srb + ) +/*+++ + +Routine Description : + + This routine will fill in the target mapping information for a + particular lun + +--*/ +{ + PISCSI_SESSION iScsiSession; + + + iScsiSession = AdapterExtension->SessionLookupTable[Srb->TargetId]; + if (IsSessionValid(iScsiSession)) + { + Mapping->UniqueSessionId = iScsiSession->SessionId; + } + + + Mapping->UniqueAdapterId = (ULONGLONG) AdapterExtension; + Mapping->OSBus = Srb->PathId; + Mapping->OSTarget = Srb->TargetId; + Mapping->OSLUN = Srb->Lun; +} + +BOOLEAN +iScsiPDOQueryWmiDataBlock( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG InstanceCount, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer + ) +/*+++ + +Routine Description : + + Called to query WMI Data blocks + +--*/ +{ + PISCSI_ADAPTER_EXTENSION adapterExtension; + PSCSI_WMI_REQUEST_BLOCK srb; + UCHAR status; + ULONG sizeNeeded = 0; + PMSiSCSI_LUNMappingInformation mapping; + + + adapterExtension = (PISCSI_ADAPTER_EXTENSION) Context; + srb = (PSCSI_WMI_REQUEST_BLOCK) DispatchContext->UserContext; + + switch (GuidIndex) { + case MSiSCSI_LUNMappingInformation_Index: + { + sizeNeeded = sizeof(MSiSCSI_LUNMappingInformation); + + if (BufferAvail >= sizeNeeded) + { + mapping = (PMSiSCSI_LUNMappingInformation)Buffer; + + iScsiBuildLUNMapping(adapterExtension, mapping, srb); + + *InstanceLengthArray = sizeNeeded; + status = SRB_STATUS_SUCCESS; + + } else { + + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + default: { + status = SRB_STATUS_ERROR; + break; + } + + } + + iSpCompleteWmiRequest(adapterExtension, srb, DispatchContext, status, sizeNeeded); + + // + // return SRB_STATUS_PENDING since the request has either already been + // completed in iSpCompleteWmiRequest or the status is really + // SRB_STATUS_PENDING. This implies that the iScsiWmiSrb routine + // may not touch the srb since it is already completed. + // + return SRB_STATUS_PENDING; + +} + + + +UCHAR +iSpBuildTargetMapping( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + _Out_writes_bytes_(BufferAvail) OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PISCSI_SESSION iScsiSession; + PMSiSCSI_TargetMappings iSCSITargetMappings; + PISCSI_TargetMapping targetMapping; + PISCSI_SESSION *sessionTable; + NTSTATUS ntStatus; + ULONG inx, jnx; + ULONG targetCount; + UCHAR status = SRB_STATUS_SUCCESS; + + *SizeNeeded = sizeof(MSiSCSI_TargetMappings); + + if (sessionTable != NULL) { + + NT_ASSERT(targetCount > 0); + + inx = 0; + while (inx < targetCount) { + + iScsiSession = sessionTable[inx]; + if (iScsiSession != NULL) { + + ULONG lunCount = 0; + + jnx = 0; + while (jnx < ISCSI_MAX_LOGICAL_UNITS) { + + if (iScsiSession->TargetLUN[jnx] != ISCSI_INVALID_LUN) { + lunCount++; + } + + jnx++; + } + + *SizeNeeded += FIELD_OFFSET(ISCSI_TargetMapping, LUNList) + + (sizeof(ISCSI_LUNList) * lunCount); + } + + inx++; + } + + if (BufferAvail >= *SizeNeeded) { + + iSCSITargetMappings = (PMSiSCSI_TargetMappings) Buffer; + + RtlZeroMemory(iSCSITargetMappings, *SizeNeeded); + + iSCSITargetMappings->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + iSCSITargetMappings->TargetMappingCount = targetCount; + + targetMapping = iSCSITargetMappings->TargetMappings; + + inx = 0; + while (inx < targetCount) { + + iScsiSession = sessionTable[inx]; + if (iScsiSession != NULL) { + + ULONG targetMappingSize; + + targetMappingSize = + FIELD_OFFSET(ISCSI_TargetMapping, LUNList); + + // + // Size needed is computed above and it is checked above + // that the buffer size provided to the function is greater + // than the size needed to fill the buffer + // + targetMapping->OSBus = 0; + + targetMapping->OSTarget = iScsiSession->OSTargetId; + + targetMapping->UniqueSessionId = iScsiSession->SessionId; + + targetMapping->FromPersistentLogin = iScsiSession->PersistentLogin; + + targetMapping->LUNCount = 0; + + jnx = 0; + while (jnx < ISCSI_MAX_LOGICAL_UNITS) { + + if (iScsiSession->TargetLUN[jnx] != ISCSI_INVALID_LUN) { + +#pragma prefast ( suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "BufferAvail is being checked against SizeNeeded above") + targetMapping->LUNList[targetMapping->LUNCount].OSLUN = + jnx; + + targetMapping->LUNList[targetMapping->LUNCount].TargetLUN = + iScsiSession->TargetLUN[jnx]; + + targetMapping->LUNCount++; + + targetMappingSize += sizeof(ISCSI_LUNList); + } + + jnx++; + } + + *(targetMapping->TargetName) = MAX_TARGET_NAME * sizeof(WCHAR); + RtlCopyMemory((targetMapping->TargetName + 1), + iScsiSession->TargetName, + (MAX_TARGET_NAME * sizeof(WCHAR))); + + targetMapping = + (PISCSI_TargetMapping) (((PUCHAR)targetMapping) + + targetMappingSize); + } + + inx++; + } + + status = SRB_STATUS_SUCCESS; + + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + } else { + if (BufferAvail >= *SizeNeeded) { + RtlZeroMemory(Buffer, BufferAvail); + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + } + + *InstanceLengthArray = *SizeNeeded; + + return status; +} + + +UCHAR +iSpBuildPortalInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PMSiSCSI_PortalInfoClass portalInfoClass; + PISCSI_PortalInfo portalInfo; + ULONG ntStatus; + ULONG inx; + UCHAR status = SRB_STATUS_SUCCESS; + + + *SizeNeeded = FIELD_OFFSET(MSiSCSI_PortalInfoClass, PortalInformation); + + *InstanceLengthArray = *SizeNeeded; + + + *SizeNeeded += sizeof(ISCSI_PortalInfo) * gNumberOfIPAddresses; + + if (BufferAvail >= *SizeNeeded) { + + portalInfoClass = (PMSiSCSI_PortalInfoClass) Buffer; + + RtlZeroMemory(portalInfoClass, *SizeNeeded); + + // + // Number of entries in PortalInformation array + // + portalInfoClass->PortalInfoCount = gNumberOfIPAddresses; + + portalInfo = portalInfoClass->PortalInformation; + + inx = 0; + while (inx < gNumberOfIPAddresses) { + + portalInfo->Index = inx; + portalInfo->Port = inx; + portalInfo->PortalTag = 0; + portalInfo->Protocol = TCP; + portalInfo->PortalType = InitiatorPortals; + + iSpCopyIPAddress(&portalInfo->IPAddr, + &(gRegisteredTransports[inx]), + NULL); + + *portalInfo->IPAddr.TextAddress = 256 * sizeof(WCHAR); + + portalInfo++; + + inx++; + } + + *InstanceLengthArray = *SizeNeeded; + + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + } else { + status = SRB_STATUS_ERROR; + *InstanceLengthArray = 0; + } + + return status; +} + + +NTSTATUS +iSpBuildHBAInformationBuffer( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PMSiSCSI_HBAInformation IScsiHBAInformation + ) +{ + NTSTATUS status; + + + // + // Boolean fields in MSiSCSI_HBAInformation by default + // are set to FALSE through RtlZeroMemory + // + RtlZeroMemory(IScsiHBAInformation, sizeof(MSiSCSI_HBAInformation)); + + // + // Unique Id we return is a pointer to + // the miniport's adapater extension + // + IScsiHBAInformation->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + // + // We want WMI to send us IP Address in binary form. + // + IScsiHBAInformation->RequiresBinaryIpAddresses = TRUE; + + // + // We use TCP/IP integrated with Windows + // + IScsiHBAInformation->IntegratedTCPIP = TRUE; + + IScsiHBAInformation->MultifunctionDevice = FALSE; + + IScsiHBAInformation->CacheValid = FALSE; + + // + // iSCSI Version supported + // + IScsiHBAInformation->VersionMin = ISCSI_CLI_VERSION_MIN; + IScsiHBAInformation->VersionMax = ISCSI_CLI_VERSION_MAX; + + IScsiHBAInformation->NumberOfPorts = 1; + + IScsiHBAInformation->MaxCDBLength = 16; + + IScsiHBAInformation->Status = 0; + + IScsiHBAInformation->FunctionalitySupported = + (ISCSI_HBA_PRESHARED_KEY_CACHE | + ISCSI_HBA_ISCSI_AUTHENTICATION_CACHE | + ISCSI_HBA_IPSEC_TUNNEL_MODE); + + *IScsiHBAInformation->VendorID = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->VendorID+1), 255, + ISCSI_VENDOR_ID, wcslen(ISCSI_VENDOR_ID)); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->VendorModel = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->VendorModel+1), 255, + ISCSI_VENDOR_MODEL, + wcslen(ISCSI_VENDOR_MODEL)); + + NT_ASSERT(NT_SUCCESS(status)); + + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->VendorVersion = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->VendorVersion+1), 255, + ISCSI_VENDOR_VERSION, + wcslen(ISCSI_VENDOR_VERSION)); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->FirmwareVersion = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->FirmwareVersion+1), 255, + ISCSI_VENDOR_VERSION, + wcslen(ISCSI_VENDOR_VERSION)); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->AsicVersion = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->AsicVersion+1), 255, + ISCSI_VENDOR_VERSION, + wcslen(ISCSI_VENDOR_VERSION)); + + + NT_ASSERT(NT_SUCCESS(status)); + + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->OptionRomVersion = 255*sizeof(WCHAR); + + *IScsiHBAInformation->SerialNumber = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->SerialNumber+1), 255, + ISCSI_SERIAL_NUMBER, + wcslen(ISCSI_SERIAL_NUMBER)); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE){ + return status; + } + + *IScsiHBAInformation->DriverName = 255*sizeof(WCHAR); + + status = RtlStringCchCopyNW((IScsiHBAInformation->DriverName+1), 255, + ISCSI_INITIATOR_DRIVER_NAME, + wcslen(ISCSI_INITIATOR_DRIVER_NAME)); + + + NT_ASSERT(NT_SUCCESS(status)); + + return status; +} + +UCHAR +iSpBuildInitiatorSessionInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWMI_CONNECTION_LIST connectionList; + ULONG size, sessionInx; + ULONG numberOfSessions, numberOfConnections; + UCHAR status; + + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, numberOfConnections); + + // + // determine the size of buffer needed to build all of the session + // and connection data structures + // + + // + // Account for the fixed part of the iScsiInitiatorSessionInfo + // + size = FIELD_OFFSET(MSiSCSI_InitiatorSessionInfo, + SessionsList); + + if (connectionList == NULL) { + if (BufferAvail >= size) + { + PMSiSCSI_InitiatorSessionInfo sessionInfo; + + sessionInfo = (PMSiSCSI_InitiatorSessionInfo)Buffer; + sessionInfo->UniqueAdapterId = (ULONGLONG) AdapterExtension; + sessionInfo->SessionCount = 0; + *SizeNeeded = size; + return(SRB_STATUS_SUCCESS); + } else { + *SizeNeeded = size; + return(SRB_STATUS_DATA_OVERRUN); + } + } + + // + // Loop over all sessions and account for the space needed for each + // session plus all of the connections within each session + // + sessionInx = 0; + while (sessionInx < numberOfSessions) { + + // + // Since the session structure needs to be 8 bytes aligned, we + // pad out to 8 bytes + // + size = (size + 7) & ~7; + + // + // Add the fixed size needed for the session structure + // + size += FIELD_OFFSET(ISCSI_SessionStaticInfo, + ConnectionsList); + + // + // Account for the size of all connection structures, being + // sure that the connection structure is padded out to 8 bytes + // in order to maintain 8 byte alignment + // + size += connectionList[sessionInx].Count * + ( (sizeof(ISCSI_ConnectionStaticInfo)+7) & ~7); + + sessionInx++; + } + + *SizeNeeded = size; + if (size <= BufferAvail) + { + // + // If we do have enough space to build the session info data + // structures then we do so + // + RtlZeroMemory(Buffer, size); + + status = iSpReadInitiatorSessionInfo( + AdapterExtension, + connectionList, + numberOfSessions, + Buffer); + + } else { + // + // If there is not enough space to build the session info data + // structures then return this error + // + status = SRB_STATUS_DATA_OVERRUN; + } + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + + return status; +} + +UCHAR +iSpBuildConnectionStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG InstanceCount, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWMI_CONNECTION_LIST connectionList; + PISCSI_CONNECTION iScsiConnection; + PWCHAR NameOffset; + PUCHAR currentDataPos; + ULONG instanceInx; + ULONG newOutBufferAvil; + WMIString DynamicInstanceName; + ULONG numberOfSessions; + ULONG numberOfConnections; + UCHAR srbStatus; + + + srbStatus = SRB_STATUS_SUCCESS; + + *SizeNeeded = 0; + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + + if (connectionList == NULL) { + DebugPrint((iScsiPrtDebugError, + "Failed to allocate array for connections\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to allocate array for connections\n"); + + return SRB_STATUS_ERROR; + } + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections); + + if (DispatchContext->MinorFunction == IRP_MN_QUERY_ALL_DATA) { + + ULONG sessionInx; + ULONG connectionInx; + ULONG connectionCount; + BOOLEAN dynamicNameStatus; + + dynamicNameStatus = ScsiPortWmiSetInstanceCount(DispatchContext, + numberOfConnections, + &newOutBufferAvil, + SizeNeeded); + if (!dynamicNameStatus) + { + DebugPrint((iScsiPrtDebugError, + "iscsiprt: wnode is not for a dynamic instance named GUID\n")); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "iscsiprt: wnode is not for a dynamic instance named GUID\n"); + + *SizeNeeded = 0; + + srbStatus = SRB_STATUS_ERROR; + + } else { + + if (newOutBufferAvil == 0) { + + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + // + // For the data itself + // + instanceInx = 0; + + sessionInx = 0; + *SizeNeeded = 0; + while (sessionInx < numberOfSessions) { + + connectionCount = connectionList[sessionInx].Count; + + connectionInx = 0; + while (connectionInx < connectionCount) { + + iScsiConnection = connectionList[sessionInx].ISCSIConnection[connectionInx]; + + if (iScsiConnection != NULL) { + + currentDataPos = (PUCHAR) ScsiPortWmiSetData(DispatchContext, + instanceInx, + sizeof(MSiSCSI_ConnectionStatistics), + &newOutBufferAvil, + SizeNeeded); + if (newOutBufferAvil == 0) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + + if ((srbStatus != SRB_STATUS_DATA_OVERRUN) && + (currentDataPos != NULL)) { + + srbStatus = iSpReadConnStatistics(AdapterExtension, + iScsiConnection, + currentDataPos); + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + } + + RtlZeroMemory(&DynamicInstanceName, + sizeof(DynamicInstanceName)); + + srbStatus = iSpGetDynamicConnectionInstanceName( + iScsiConnection, + &DynamicInstanceName); + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + + NameOffset = ScsiPortWmiSetInstanceName( + DispatchContext, + instanceInx, + DynamicInstanceName.Length+sizeof(USHORT), + &newOutBufferAvil, + SizeNeeded); + + if ((newOutBufferAvil == 0) && (NameOffset == NULL)) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + if (srbStatus != SRB_STATUS_DATA_OVERRUN) + { + // + // copy the instance name into NameOffset + // + RtlCopyMemory(NameOffset, (PUCHAR)(&DynamicInstanceName), + (DynamicInstanceName.Length + sizeof(USHORT))); + } + + instanceInx++; + } + + connectionInx++; + } + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + + sessionInx++; + } + } + } else { + + PWMIString instanceName; + ULONG givenInstanceNameLength = 0; + ULONG dynInstanceNameLength = 0; + ULONG instanceNameLength; + ULONG sessionInx; + ULONG connectionInx; + ULONG connectionCount; + BOOLEAN found = FALSE; + + // + // single instance + // + + srbStatus = SRB_STATUS_ERROR; + + // + // get the instance name + // + instanceName = (PWMIString)ScsiPortWmiGetInstanceName(DispatchContext); + + if (instanceName != NULL) + { + givenInstanceNameLength = instanceName->Length / sizeof(instanceName->Buffer[0]); + + *SizeNeeded = sizeof(MSiSCSI_ConnectionStatistics); + if (BufferAvail < *SizeNeeded) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + + } else { + + instanceInx = 0; + + sessionInx = 0; + + while (sessionInx < numberOfSessions) { + + if (connectionList[sessionInx].Count) { + + connectionInx = 0; + + while (connectionInx < numberOfConnections) { + iScsiConnection = connectionList[sessionInx].ISCSIConnection[0]; + + if (iScsiConnection != NULL) { + + RtlZeroMemory(&DynamicInstanceName, + sizeof(DynamicInstanceName)); + + srbStatus = iSpGetDynamicConnectionInstanceName( + iScsiConnection, + &DynamicInstanceName); + + if (srbStatus != SRB_STATUS_ERROR) + { + dynInstanceNameLength = DynamicInstanceName.Length / sizeof(DynamicInstanceName.Buffer[0]); + + if ((givenInstanceNameLength == dynInstanceNameLength) && + !wcsncmp( + DynamicInstanceName.Buffer, + instanceName->Buffer, + dynInstanceNameLength)) { + + srbStatus = iSpReadConnStatistics(AdapterExtension, + iScsiConnection, + Buffer); + + if (srbStatus == SRB_STATUS_SUCCESS) + { + *InstanceLengthArray = *SizeNeeded; + } + + found = TRUE; + + break; + } + } + } + + connectionInx++; + } + } + + if (found == TRUE) { + break; + } + + sessionInx++; + } + } + } else { + srbStatus = SRB_STATUS_ERROR; + } + + if(srbStatus != SRB_STATUS_SUCCESS && + srbStatus != SRB_STATUS_DATA_OVERRUN) + { + *SizeNeeded = 0; + } + } + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + + return srbStatus; +} + +UCHAR +iSpBuildSessionStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG InstanceCount, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWCHAR NameOffset; + PUCHAR currentDataPos; + WMIString DynamicInstanceName; + ULONG connectionCount=0; + ULONG instanceInx; + ULONG newOutBufferAvil; + ULONG initiatorIndx; + ULONG instanceSize=0; + WMIString WMIformatString; + UCHAR srbStatus; + + PWMI_CONNECTION_LIST connectionList; + ULONG numberOfSessions; + ULONG numberOfConnections; + + + srbStatus = SRB_STATUS_SUCCESS; + *SizeNeeded = 0; + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + + if (connectionList == NULL) { + DebugPrint((iScsiPrtDebugError, + "Failed to allocate array for connections\n")); + + ETWDebugPrint(iScsiLevelError, iScsiFlagWmi, + "Failed to allocate array for connections\n"); + + return SRB_STATUS_ERROR; + } + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections); + + if (DispatchContext->MinorFunction == IRP_MN_QUERY_ALL_DATA) + { + + ULONG sessionInx; + BOOLEAN dynamicNameStatus; + + // + // instance counts + // + dynamicNameStatus = ScsiPortWmiSetInstanceCount(DispatchContext, + numberOfSessions, + &newOutBufferAvil, + SizeNeeded); + + if (!dynamicNameStatus) + { + DebugPrint((iScsiPrtDebugError, + "iscsiprt: wnode is not for a dynamic instance named GUID\n")); + + ETWDebugPrint(iScsiLevelError, iScsiFlagWmi, + "iscsiprt: wnode is not for a dynamic instance named GUID\n"); + + *SizeNeeded = 0; + srbStatus = SRB_STATUS_ERROR; + + } else { + + if (numberOfSessions == 0) + { + // + // no instances avaliable + // + } else { + + if (newOutBufferAvil == 0) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + // + // for the data itself + // + instanceInx = 0; + + sessionInx = 0; + + *SizeNeeded = 0; + + while (sessionInx < numberOfSessions) { + + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + + if (connectionList[sessionInx].Count > 0) { + + iScsiConnection = connectionList[sessionInx].ISCSIConnection[0]; + iScsiSession = iScsiConnection->ISCSISession; + + currentDataPos = (PUCHAR) ScsiPortWmiSetData(DispatchContext, + instanceInx, + sizeof(MSiSCSI_SessionStatistics), + &newOutBufferAvil, + SizeNeeded); + if (newOutBufferAvil == 0) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + if ((srbStatus != SRB_STATUS_DATA_OVERRUN) && + (currentDataPos != NULL)) + { + + srbStatus = iSpReadSessionStatistics(AdapterExtension, + iScsiSession, + &connectionList[sessionInx], + currentDataPos); + + } + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + + RtlZeroMemory(&DynamicInstanceName, + sizeof(DynamicInstanceName)); + + srbStatus = iSpGetDynamicSessionInstanceName(iScsiSession, + &DynamicInstanceName); + + NameOffset = ScsiPortWmiSetInstanceName(DispatchContext, + instanceInx, + DynamicInstanceName.Length+sizeof(USHORT), + &newOutBufferAvil, + SizeNeeded); + + if ((newOutBufferAvil == 0) && (NameOffset == NULL)) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + if (srbStatus != SRB_STATUS_DATA_OVERRUN) { + + // + // copy the instance name into NameOffset + // + RtlCopyMemory(NameOffset, + (PUCHAR)(&DynamicInstanceName), + (DynamicInstanceName.Length + sizeof(USHORT))); + } + + instanceInx++; + } + + sessionInx++; + } + + + } + } + } else { //single instance + + PWMIString instanceName; + ULONG givenInstanceNameLength = 0; + ULONG dynInstanceNameLength = 0; + ULONG instanceNameLength; + ULONG sessionInx; + BOOLEAN found = FALSE; + + srbStatus = SRB_STATUS_ERROR; + + // + // get the instance name + // + instanceName = (PWMIString) ScsiPortWmiGetInstanceName(DispatchContext); + + if (instanceName != NULL) + { + givenInstanceNameLength = instanceName->Length / sizeof(instanceName->Buffer[0]); + + *SizeNeeded = sizeof(MSiSCSI_SessionStatistics); + if (BufferAvail < *SizeNeeded) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } else { + + sessionInx = 0; + while (sessionInx < numberOfSessions) { + + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + + if (connectionList[sessionInx].Count > 0) { + + iScsiConnection = connectionList[sessionInx].ISCSIConnection[0]; + iScsiSession = iScsiConnection->ISCSISession; + + RtlZeroMemory(&DynamicInstanceName, sizeof(DynamicInstanceName)); + srbStatus = iSpGetDynamicSessionInstanceName(iScsiSession, + &DynamicInstanceName); + if (srbStatus == SRB_STATUS_SUCCESS) + { + dynInstanceNameLength = DynamicInstanceName.Length / sizeof(DynamicInstanceName.Buffer[0]); + + if (givenInstanceNameLength == dynInstanceNameLength + && !wcsncmp(DynamicInstanceName.Buffer, + instanceName->Buffer, + dynInstanceNameLength)) + { + srbStatus = iSpReadSessionStatistics(AdapterExtension, + iScsiSession, + &connectionList[sessionInx], + Buffer); + + if (srbStatus == SRB_STATUS_SUCCESS) + { + *InstanceLengthArray = *SizeNeeded; + } + + break; + } + } + } + + sessionInx++; + } + } + } else { + srbStatus = SRB_STATUS_ERROR; + } + + if(srbStatus != SRB_STATUS_SUCCESS && + srbStatus != SRB_STATUS_DATA_OVERRUN) + { + *SizeNeeded = 0; + } + } + + + return srbStatus; +} + +UCHAR +iSpBuildRequestTimeStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG InstanceCount, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWMI_CONNECTION_LIST connectionList; + PISCSI_CONNECTION iScsiConnection; + PWCHAR NameOffset; + PUCHAR currentDataPos; + ULONG instanceInx; + ULONG newOutBufferAvil; + WMIString DynamicInstanceName; + ULONG numberOfSessions; + ULONG numberOfConnections; + UCHAR srbStatus; + + + srbStatus = SRB_STATUS_SUCCESS; + + *SizeNeeded = 0; + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + if (connectionList == NULL) { + + DebugPrint((iScsiPrtDebugError, + "Failed to allocate array for connections\n")); + + ETWDebugPrint(iScsiLevelError, iScsiFlagWmi, + "Failed to allocate array for connections\n"); + + return SRB_STATUS_ERROR; + } + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections); + + if (DispatchContext->MinorFunction == IRP_MN_QUERY_ALL_DATA) { + + ULONG sessionInx; + ULONG connectionInx; + ULONG connectionCount; + BOOLEAN dynamicNameStatus; + + dynamicNameStatus = ScsiPortWmiSetInstanceCount(DispatchContext, + numberOfConnections, + &newOutBufferAvil, + SizeNeeded); + if (!dynamicNameStatus) + { + DebugPrint((iScsiPrtDebugError, + "iscsiprt: wnode is not for a dynamic instance named GUID\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "iscsiprt: wnode is not for a dynamic instance named GUID\n"); + + *SizeNeeded = 0; + + srbStatus = SRB_STATUS_ERROR; + + } else { + + if (newOutBufferAvil == 0) { + + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + // + // For the data itself + // + instanceInx = 0; + + sessionInx = 0; + + *SizeNeeded = 0; + + while (sessionInx < numberOfSessions) { + + connectionCount = connectionList[sessionInx].Count; + + connectionInx = 0; + while (connectionInx < connectionCount) { + + iScsiConnection = connectionList[sessionInx].ISCSIConnection[connectionInx]; + + if (iScsiConnection != NULL) { + + currentDataPos = (PUCHAR) ScsiPortWmiSetData(DispatchContext, + instanceInx, + sizeof(MSiSCSI_RequestTimeStatistics), + &newOutBufferAvil, + SizeNeeded); + if (newOutBufferAvil == 0) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + + if ((srbStatus != SRB_STATUS_DATA_OVERRUN) && + (currentDataPos != NULL)) { + + srbStatus = iSpReadRequestTimeStatistics(AdapterExtension, + iScsiConnection, + currentDataPos); + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + } + + RtlZeroMemory(&DynamicInstanceName, + sizeof(DynamicInstanceName)); + + srbStatus = iSpGetDynamicConnectionInstanceName( + iScsiConnection, + &DynamicInstanceName); + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + + NameOffset = ScsiPortWmiSetInstanceName( + DispatchContext, + instanceInx, + DynamicInstanceName.Length+sizeof(USHORT), + &newOutBufferAvil, + SizeNeeded); + + if ((newOutBufferAvil == 0) && (NameOffset == NULL)) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + if (srbStatus != SRB_STATUS_DATA_OVERRUN) + { + // + // copy the instance anme into NameOffset + // + RtlCopyMemory(NameOffset, (PUCHAR)(&DynamicInstanceName), + (DynamicInstanceName.Length + sizeof(USHORT))); + } + + instanceInx++; + } + + connectionInx++; + } + + if (srbStatus == SRB_STATUS_ERROR) + { + break; + } + + sessionInx++; + } + } + } else { + PWMIString instanceName; + ULONG givenInstanceNameLength = 0; + ULONG dynInstanceNameLength = 0; + ULONG instanceNameLength; + ULONG sessionInx; + ULONG connectionInx; + ULONG connectionCount; + BOOLEAN found = FALSE; + + // + // single instance + // + + srbStatus = SRB_STATUS_ERROR; + + // + // get the instance name + // + instanceName = (PWMIString)ScsiPortWmiGetInstanceName(DispatchContext); + + if (instanceName != NULL) + { + givenInstanceNameLength = instanceName->Length / sizeof(instanceName->Buffer[0]); + + *SizeNeeded = sizeof(MSiSCSI_RequestTimeStatistics); + if (BufferAvail < *SizeNeeded) + { + // + // The buffer passed to return the data is too small + // + srbStatus = SRB_STATUS_DATA_OVERRUN; + + } else { + + instanceInx = 0; + + sessionInx = 0; + + while (sessionInx < numberOfSessions) { + + if (connectionList[sessionInx].Count) { + + connectionInx = 0; + + while (connectionInx < numberOfConnections) { + iScsiConnection = connectionList[sessionInx].ISCSIConnection[0]; + + if (iScsiConnection != NULL) { + + srbStatus = iSpGetDynamicConnectionInstanceName( + iScsiConnection, + &DynamicInstanceName); + + if (srbStatus != SRB_STATUS_ERROR) + { + dynInstanceNameLength = DynamicInstanceName.Length / sizeof(DynamicInstanceName.Buffer[0]); + + if ((givenInstanceNameLength == dynInstanceNameLength) && + !wcsncmp(DynamicInstanceName.Buffer, + instanceName->Buffer, + dynInstanceNameLength)) + { + srbStatus = iSpReadRequestTimeStatistics(AdapterExtension, + iScsiConnection, + Buffer); + if (srbStatus == SRB_STATUS_SUCCESS) + { + *InstanceLengthArray = *SizeNeeded; + } + + found = TRUE; + + break; + } + } + } + connectionInx++; + } + } + + if (found == TRUE) { + break; + } + + sessionInx++; + } + } + } else { + srbStatus = SRB_STATUS_ERROR; + } + + if(srbStatus != SRB_STATUS_SUCCESS && + srbStatus != SRB_STATUS_DATA_OVERRUN) + { + *SizeNeeded = 0; + } + } + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + + return srbStatus; +} + + +UCHAR iScsiQuerySecurityCapabilities( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferAvail, + PUCHAR Buffer, + PULONG InstanceLength, + PULONG SizeNeeded + ) +/*+++ + +Routine Description : + + This routine implements the WMI query for the security capabilites + class. + +--*/ +{ + UCHAR status; + PMSiSCSI_SecurityCapabilities config; + + + *SizeNeeded = sizeof(MSiSCSI_SecurityCapabilities); + + if (BufferAvail >= sizeof(MSiSCSI_SecurityCapabilities)) + { + config = (PMSiSCSI_SecurityCapabilities)Buffer; + RtlZeroMemory(Buffer, sizeof(MSiSCSI_SecurityCapabilities)); + + config->ProtectiScsiTraffic = FALSE; + config->ProtectiSNSTraffic = FALSE; + config->CertificatesSupported = FALSE; + + config->EncryptionAvailableCount = 1; + config->EncryptionAvailable[0] = ISCSI_ENCRYPT_NONE; + + *InstanceLength = *SizeNeeded; + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + return(status); +} + +UCHAR iScsiQueryDiscoveryConfig( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferAvail, + PUCHAR Buffer, + PULONG InstanceLength, + PULONG SizeNeeded + ) +/*+++ + +Routine Description : + + This routine implements the WMI query for the discovery config + class. + +--*/ +{ + NTSTATUS rtlStatus; + UCHAR status; + PMSiSCSI_DiscoveryConfig config; + + + *SizeNeeded = sizeof(MSiSCSI_DiscoveryConfig); + + if (BufferAvail >= sizeof(MSiSCSI_DiscoveryConfig)) + { + config = (PMSiSCSI_DiscoveryConfig)Buffer; + RtlZeroMemory(Buffer, sizeof(MSiSCSI_DiscoveryConfig)); + if (AdapterExtension->DiscoveryConfigFlags & DISCOVERY_CONFIG_DO_DISCOVERY) + { + config->PerformiSNSDiscovery = TRUE; + } + + if (AdapterExtension->DiscoveryConfigFlags & DISCOVERY_CONFIG_FIND_SNS_AUTOMATICALLY) + { + config->AutomaticiSNSDiscovery = TRUE; + } + + config->InitiatorName[0] = 256 * sizeof(WCHAR); + + rtlStatus = RtlStringCchCopyNW(&config->InitiatorName[1], + MAX_INITIATOR_NAME, + AdapterExtension->InitiatorName, + MAX_INITIATOR_NAME); + + config->iSNSServer.Type = ISCSI_IP_ADDRESS_TEXT; + config->iSNSServer.TextAddress[0] = 256 * sizeof(WCHAR); + rtlStatus = RtlStringCchCopyNW(&config->iSNSServer.TextAddress[1], 256, + AdapterExtension->SNSServer, 256); + + *InstanceLength = *SizeNeeded; + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + return(status); +} + +UCHAR iScsiAdvanceString( + OUT PWCHAR *String, + OUT PUSHORT StringLen, + IN OUT PUCHAR *Buffer, + IN OUT PULONG BufferSize + ) +{ + UCHAR status = SRB_STATUS_ERROR; + PUCHAR b; + ULONG bs; + USHORT len; + + b = *Buffer; + bs = *BufferSize; + + if (bs >= sizeof(USHORT)) + { + // + // Get the length of the string and advance beyond it + // + len = *((PUSHORT)b); + b += sizeof(USHORT); + bs -= sizeof(USHORT); + *String = (PWCHAR)b; + *StringLen = len; + + if (bs >= len) + { + b += len; + bs -= len; + + *Buffer = b; + *BufferSize = bs; + status = SRB_STATUS_SUCCESS; + } + } + return(status); +} + +UCHAR iScsiSetDiscoveryConfig( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferSize, + PUCHAR Buffer + ) +/*+++ + +Routine Description : + + This routine implements the WMI set for the discovery config + class. + +--*/ +{ + NTSTATUS rtlStatus; + UCHAR status; + PMSiSCSI_DiscoveryConfig config; + USHORT stringLen, initiatorNameLen; + PISCSI_IP_Address ipAddress; + PWCHAR string; + PWCHAR initiatorName; + ULONG pad; + + // + // Assume the buffer passed will be bad in some way + // + status = SRB_STATUS_ERROR; + + // + // Validate that the buffer passed is large enough for the + // beginning of the class + // + if (BufferSize >= FIELD_OFFSET(MSiSCSI_DiscoveryConfig, + InitiatorName)) + { + config = (PMSiSCSI_DiscoveryConfig)Buffer; + + // + // Advance buffer pointer past beginning of config struct + // + Buffer += FIELD_OFFSET(MSiSCSI_DiscoveryConfig, InitiatorName); + BufferSize -= FIELD_OFFSET(MSiSCSI_DiscoveryConfig, InitiatorName); + + // + // Now validate that there is a valid InitiatorName string + // + status = iScsiAdvanceString(&initiatorName, + &initiatorNameLen, + &Buffer, + &BufferSize); + + if (status == SRB_STATUS_SUCCESS) + { + status = SRB_STATUS_ERROR; + + // + // Pad Buffer to a 4 byte boundry since + // ISCSI_IP_Address is required to be on a 4 byte + // boundry + // + pad = (ULONG)((((ULONG_PTR)Buffer + 3) &~3) - (ULONG_PTR)Buffer); + if (BufferSize >= pad) + { + Buffer += pad; + BufferSize -= pad; + + // + // Now validate that there is enough room for the beginning of + // the IP address struct + // + if (BufferSize >= FIELD_OFFSET(ISCSI_IP_Address, + TextAddress)) + { + ipAddress = (PISCSI_IP_Address)Buffer; + + // + // Advance buffer pointer beyond IP address struct + // + Buffer += FIELD_OFFSET(ISCSI_IP_Address, TextAddress); + BufferSize -= FIELD_OFFSET(ISCSI_IP_Address, TextAddress); + + // + // Validate that the user passed a text addresss + // + if ((ipAddress->Type == ISCSI_IP_ADDRESS_TEXT) || + (ipAddress->Type == ISCSI_IP_ADDRESS_IPV4)) + { + // + // Validate that there is enough room for the string + // length + // + status = iScsiAdvanceString(&string, + &stringLen, + &Buffer, + &BufferSize); + + if (status == SRB_STATUS_SUCCESS) + { + status = SRB_STATUS_ERROR; + + // + // Finally copy out the values from the + // passed buffer into the device extension + // + + // + // Validate that the input string is not too large + // + if (initiatorNameLen <= MAX_INITIATOR_NAME) { + + rtlStatus = RtlStringCchCopyNW(AdapterExtension->InitiatorName, + MAX_INITIATOR_NAME, + initiatorName, + MAX_INITIATOR_NAME); + AdapterExtension->InitiatorName[(initiatorNameLen / sizeof(WCHAR))] = 0; + + if (ipAddress->Type == ISCSI_IP_ADDRESS_TEXT) + { + if (stringLen <= 256) + { + rtlStatus = RtlStringCchCopyNW(AdapterExtension->SNSServer, + 256, string, 256); + AdapterExtension->SNSServer[(stringLen / sizeof(WCHAR))] = 0; + } + + } else { + PUCHAR i; + + i = (PUCHAR)&ipAddress->IpV4Address; + + RtlStringCchPrintfW(AdapterExtension->SNSServer, + 256, + L"%d.%d.%d.%d", + i[0], i[1], i[2], i[3]); + } + AdapterExtension->DiscoveryConfigFlags = (config->PerformiSNSDiscovery) ? + DISCOVERY_CONFIG_DO_DISCOVERY : + 0; + + AdapterExtension->DiscoveryConfigFlags |= (config->AutomaticiSNSDiscovery) ? + DISCOVERY_CONFIG_FIND_SNS_AUTOMATICALLY : + 0; + + status = SRB_STATUS_SUCCESS; + } + } + } + } + } + } + } + return(status); +} + +UCHAR iScsiAddPortalGroup( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN ULONG PortalCount + ) +/*+++ + +Routine Description : + + This routine will allocate space of an + ISCSI_DiscoveredTargetPortalGroup structure that can be followed by + a set of ISCSI_DiscoveredTargetPortal data structures that describe + the portals associated with the portal group. + + *Buffer on entry has the current position in the buffer that the + data structures are being built. On return it is updated beyond + the ISCSI_DiscoveredTargetPortalGroup structure. + + *SizeLeft on entry has the number of bytes left in *Buffer. On + return it is updated with the number of bytes consumed by the + ISCSI_DiscoveredTargetPortalGroup structure. If there is not + enough bytes for the ISCSI_DiscoveredTargetPortalGroup + structure then it returns with 0 and SRB_STATUS_DATA_OVERRUN is + the return value from this function. If there is enough bytes + then SRB_STATUS_SUCCESS is returned. If a previous call to this + or iScsiAddPortalToGroup returned *SizeLeft as 0, then it is + permissible to keep calling so that *SizeNeeded gets updated so + that an accurate size for the entire data structure can be + computed. + + *SizeNeeded on entry has the number of bytes needed so far to complete the + request. On return it is updated to include the number of bytes + needed for the ISCSI_DiscoveredTargetPortalGroup structure. + + *PortalGroup returns pointing at the portal group for which space + was allocated by this routine. + +--*/ +{ + UCHAR status; + ULONG PadSize, GroupSize, TotalSize; + PISCSI_DiscoveredTargetPortalGroup2 PortalGroup; + + // + // Be sure that buffer is padded on a 4 byte boundry + // + PadSize = (ULONG)((((ULONG_PTR)*Buffer + 3) &~3) - ((ULONG_PTR)*Buffer)); + + // + // Compute size of portal groups + // + GroupSize = FIELD_OFFSET(ISCSI_DiscoveredTargetPortalGroup2, + Portals); + TotalSize = PadSize + GroupSize; + + // + // Update the size needed to complete the entire request + // + *SizeNeeded += TotalSize; + + if (*SizeLeft >= TotalSize) + { + // + // There is enough room to build the portal group. Return the + // pointer to the portal group. + // + RtlZeroMemory(*Buffer, TotalSize); + + PortalGroup = (PISCSI_DiscoveredTargetPortalGroup2)((PUCHAR)*Buffer + + PadSize); + PortalGroup->PortalCount = PortalCount; + + // + // Update pointer in current buffer and number of bytes left + // + *SizeLeft -= TotalSize; + status = SRB_STATUS_SUCCESS; + } else { + // + // There is not enough room left to build the portal group + // + *SizeLeft = 0; + status = SRB_STATUS_DATA_OVERRUN; + } + + // + // Advance buffer pointer, do this even if there is not enough room + // so the size calculations can take into account any padding + // + *Buffer += TotalSize; + + return(status); +} + +VOID +iScsiCopyUTF8ToCounted( + PWCHAR p, + PUTF8CHAR UTF8, + ULONG UTF8Len + ) +{ + ULONG i; + + *p++ = ((USHORT)UTF8Len * sizeof(WCHAR)); + for (i = 0; i < UTF8Len; i++) + { + // + // This is a quick and dirty conversion from UTF8 to + // UNICODE and is only valid for the US ANSI character set. + // See RFC 2044 for more details on converting UTF8 to + // UNICODE + // + *p++ = (WCHAR)*UTF8++; + } +} + +UCHAR iScsiAddPortalToGroup( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN ULONG Address, + IN PUTF8CHAR SymbolicName, + IN USHORT Socket, + IN ULONG SecurityBitmap, + IN ULONG KeySize, + IN PUCHAR Key + ) +/*+++ + +Routine Description : + + This routine will allocate space of an + ISCSI_DiscoveredTargetPortal structure and fill it with the + parameters passed as appropriate. + + *Buffer on entry has the current position in the buffer that the + data structures are being built. On return it is updated beyond + the ISCSI_DiscoveredTargetPortal structure. + + *SizeLeft on entry has the number of bytes left in *Buffer. On + return it is updated with the number of bytes consumed by the + ISCSI_DiscoveredTargetPortal structure. If there is not + enough bytes for the ISCSI_DiscoveredTargetPortal + structure then it returns with 0 and SRB_STATUS_DATA_OVERRUN is + the return value from this function. If there is enough bytes + then SRB_STATUS_SUCCESS is returned. If a previous call to this + or iScsiAddPortalGroup returned *SizeLeft as 0, then it is + permissible to keep calling so that *SizeNeeded gets updated so + that an accurate size for the entire data structure can be + computed. + + *SizeNeeded on entry has the number of bytes needed so far to complete the + request. On return it is updated to include the number of bytes + needed for the ISCSI_DiscoveredTargetPortal structure. + + Address has the IP Address of the portal + + SymbolicName is a pointer to a UTF8 string that has the portal + symbolic name. + + Socket has the socket number of the portal + + SecurityBitmap is the security bitmap + + KeySize is the number of bytes in the key + + Key is th preshared key + +--*/ +{ + UCHAR status; + PISCSI_DiscoveredTargetPortal2 Portal; + ULONG PadSize, SymbolicNamePos, SymbolicNameLen, PortalSize; + ULONG TotalSize, i; + PWCHAR p; + PULONG pu; + ULONG BitmapPos; + + // + // Portal must be padded on a 4 byte boundry + // + PadSize = (ULONG)((((ULONG_PTR)*Buffer + 3) &~3) - ((ULONG_PTR)*Buffer)); + + // + // Compute the portal size out of the size of the individual + // components. Since these structures are variable length we cannot + // use sizeof() without being very wasteful of memory + // + BitmapPos = FIELD_OFFSET(ISCSI_DiscoveredTargetPortal2, Address) + + FIELD_OFFSET(ISCSI_IP_Address, TextAddress) + + sizeof(USHORT); // 0 length for IP_Address->TextAddress + + SymbolicNamePos = BitmapPos + (2 * sizeof(ULONG)) + KeySize; + + SymbolicNameLen = SymbolicName ? strlen(SymbolicName) : 0; + PortalSize = SymbolicNamePos + + // USHORT for length and size in WCHAR of + // symbolic name + sizeof(USHORT) + (SymbolicNameLen * sizeof(WCHAR)); + + TotalSize = PadSize + PortalSize; + *SizeNeeded += TotalSize; + + if (*SizeLeft >= TotalSize) + { + // + // There is enough room for the portal so build the portal data + // structure + // + Portal = (PISCSI_DiscoveredTargetPortal2)((PUCHAR)*Buffer + PadSize); + + RtlZeroMemory(Portal, TotalSize); + Portal->Socket = Socket; + Portal->Address.Type = ISCSI_IP_ADDRESS_IPV4; + Portal->Address.IpV4Address = Address; + Portal->Address.TextAddress[0] = 0; + + pu = (PULONG)((PUCHAR)Portal + BitmapPos); + + *pu++ = SecurityBitmap; + *pu++ = KeySize; + + memcpy(pu, Key, KeySize); + + // + // FIll in symbolic name; length followed by unicode chars + // + p = (PWCHAR)((PUCHAR)Portal + SymbolicNamePos); + + iScsiCopyUTF8ToCounted(p, SymbolicName, SymbolicNameLen); + + // + // Update our current buffer pointers + // + *SizeLeft -= TotalSize; + + status = SRB_STATUS_SUCCESS; + } else { + // + // There is not enough room for the portal + // + *SizeLeft = 0; + status = SRB_STATUS_DATA_OVERRUN; + } + + // + // Advance buffer pointer, do this even if there is not enough room + // so the size calculations can take into account any padding + // + *Buffer += TotalSize; + + return(status); +} + +UCHAR iScsiAddDiscoveredTarget( + IN OUT PUCHAR *Buffer, + IN OUT PULONG SizeLeft, + IN OUT PULONG SizeNeeded, + IN PUTF8CHAR Name, + IN PUTF8CHAR Alias, + IN PUTF8CHAR DDName, + IN ULONG DDID, + IN ULONG PortalGroupCount + ) +/*+++ + +Routine Description : + + This routine will allocate space of an + ISCSI_DiscoveredTargetPortal structure and fill it with the + parameters passed as appropriate. + + *Buffer on entry has the current position in the buffer that the + data structures are being built. On return it is updated beyond + the ISCSI_DiscoveredTargetPortal structure. + + *SizeLeft on entry has the number of bytes left in *Buffer. On + return it is updated with the number of bytes consumed by the + ISCSI_DiscoveredTargetPortal structure. If there is not + enough bytes for the ISCSI_DiscoveredTargetPortal + structure then it returns with 0 and SRB_STATUS_DATA_OVERRUN is + the return value from this function. If there is enough bytes + then SRB_STATUS_SUCCESS is returned. If a previous call to this + or iScsiAddPortalGroup returned *SizeLeft as 0, then it is + permissible to keep calling so that *SizeNeeded gets updated so + that an accurate size for the entire data structure can be + computed. + + *SizeNeeded on entry has the number of bytes needed so far to complete the + request. On return it is updated to include the number of bytes + needed for the ISCSI_DiscoveredTargetPortal structure. + + Name is the target name + + Alias is the target alias + + DDName is the Discovery domain name + + DDID is dicovery domain id + +--*/ +{ + UCHAR status; + ULONG NameLen, AliasLen, DDNameLen, PadSize, TotalSize; + PWCHAR p; + PISCSI_DiscoveredTarget2 Target; + + NameLen = strlen(Name); + AliasLen = Alias ? strlen(Alias) : 0; + + PadSize = (ULONG)((((ULONG_PTR)*Buffer + 3) &~3) - ((ULONG_PTR)*Buffer)); + + TotalSize = FIELD_OFFSET(ISCSI_DiscoveredTarget2, TargetName) + + (((NameLen+1) + (AliasLen+1) ) * sizeof(WCHAR)) + + PadSize; + + *SizeNeeded += TotalSize; + + if (*SizeLeft >= TotalSize) + { + Target = (PISCSI_DiscoveredTarget2)((PUCHAR)*Buffer + PadSize); + + Target->TargetPortalGroupCount = PortalGroupCount; + + p = (PWCHAR)((PUCHAR)Target + FIELD_OFFSET(ISCSI_DiscoveredTarget2, + TargetName)); + iScsiCopyUTF8ToCounted(p, Name, NameLen); + p += NameLen + 1; + + iScsiCopyUTF8ToCounted(p, Alias, AliasLen); + p += AliasLen + 1; + + *SizeLeft -= TotalSize; + status = SRB_STATUS_SUCCESS; + } else { + // + // There is not enough room for the portal + // + *SizeLeft = 0; + status = SRB_STATUS_DATA_OVERRUN; + } + + // + // Advance buffer pointer, do this even if there is not enough room + // so the size calculations can take into account any padding + // + *Buffer += TotalSize; + + return(status); +} + +UCHAR iScsiSetPresharedKeyForId( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG InBufferSize, + ULONG OutBufferSize, + PULONG SizeNeeded, + PUCHAR Buffer + ) +{ + PSetPresharedKeyForId_IN in; + PSetPresharedKeyForId_OUT out; + UCHAR status; + ULONG sizeExpected; + PCHAR key; + + *SizeNeeded = sizeof(SetPresharedKeyForId_OUT); + + if (OutBufferSize >= *SizeNeeded) + { + status = SRB_STATUS_ERROR; + if (InBufferSize >= FIELD_OFFSET(SetPresharedKeyForId_IN, + Id)) + { + in = (PSetPresharedKeyForId_IN)Buffer; + sizeExpected = FIELD_OFFSET(SetPresharedKeyForId_IN, + Id) + + in->IdSize + + in->KeySize; + if (InBufferSize >= sizeExpected) + { + key = OffsetToPtr(in, FIELD_OFFSET(SetPresharedKeyForId_IN, + Id) + + in->IdSize); + + DebugPrint((iScsiPrtDebugError, + "iScsiSetPresharedKeyForId: in %p type %d idlen %x at %p KeyLen is %x at %p\n", + in, + in->IdType, + in->IdSize, + in->Id, + in->KeySize, + key)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "iScsiSetPresharedKeyForId: in %p type %d idlen %x at %p KeyLen is %x at %p\n", + in, + in->IdType, + in->IdSize, + in->Id, + in->KeySize, + key); + + out = (PSetPresharedKeyForId_OUT)Buffer; + out->Status = STATUS_SUCCESS; + status = SRB_STATUS_SUCCESS; + } + } + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + return(status); +} + + +UCHAR iScsiSetGroupPresharedKey( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG InBufferSize, + ULONG OutBufferSize, + PULONG SizeNeeded, + PUCHAR Buffer + ) +{ + PSetGroupPresharedKey_IN in; + PSetGroupPresharedKey_OUT out; + UCHAR status; + ULONG sizeExpected; + + *SizeNeeded = sizeof(SetGroupPresharedKey_OUT); + + if (OutBufferSize >= *SizeNeeded) + { + status = SRB_STATUS_ERROR; + if (InBufferSize >= FIELD_OFFSET(SetGroupPresharedKey_IN, + Key)) + { + in = (PSetGroupPresharedKey_IN)Buffer; + sizeExpected = FIELD_OFFSET(SetGroupPresharedKey_IN, + Key) + in->KeySize; + if (InBufferSize >= sizeExpected) + { + DebugPrint((iScsiPrtDebugError, + "iScsiSetGroupPresharedKey: in %p KeyLen is %x at %p\n", + in, + in->KeySize, + in->Key)); + + ETWDebugPrint(iScsiLevelError, iScsiFlagWmi, + "iScsiSetGroupPresharedKey: in %p KeyLen is %x at %p\n", + in, + in->KeySize, + in->Key); + + out = (PSetGroupPresharedKey_OUT)Buffer; + out->Status = STATUS_SUCCESS; + status = SRB_STATUS_SUCCESS; + } + } + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + return(status); +} + +UCHAR iScsiSetTunnelModeOuterAddress( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG InBufferSize, + ULONG OutBufferSize, + PULONG SizeNeeded, + PUCHAR Buffer + ) +{ + PSetTunnelModeOuterAddress_IN in; + PSetTunnelModeOuterAddress_OUT out; + UCHAR status; + ULONG sizeExpected; + + *SizeNeeded = sizeof(SetTunnelModeOuterAddress_OUT); + + if (OutBufferSize >= *SizeNeeded) + { + status = SRB_STATUS_ERROR; + if (InBufferSize >= sizeof(SetTunnelModeOuterAddress_IN)) + { + in = (PSetTunnelModeOuterAddress_IN)Buffer; + + DebugPrint((iScsiPrtDebugError, + "iScsiSetTunnelModeOuterAddress: in %p port %x\n", + in, + in->PortNumber)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "iScsiSetTunnelModeOuterAddress: in %p port %x\n", + in, + in->PortNumber); + + out = (PSetTunnelModeOuterAddress_OUT)Buffer; + out->Status = STATUS_SUCCESS; + status = SRB_STATUS_SUCCESS; + } + } else { + status = SRB_STATUS_DATA_OVERRUN; + } + + return(status); +} + +UCHAR iScsiReportDiscoveredTargets2( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG BufferSize, + PULONG SizeNeeded, + PUCHAR Buffer + ) +{ + UCHAR status; + PReportDiscoveredTargets2_OUT out; + ULONG size; + + + *SizeNeeded = FIELD_OFFSET(ReportDiscoveredTargets2_OUT, + Targets); + if (BufferSize >= *SizeNeeded) + { + out = (PReportDiscoveredTargets2_OUT)Buffer; + out->Status = STATUS_SUCCESS; + out->TargetCount = 3; + + BufferSize -= *SizeNeeded; + } + + // + // Advance buffer pointer, do this even if there is not enough room + // so the size calculations can take into account any padding + // + Buffer += *SizeNeeded; + + iScsiAddDiscoveredTarget(&Buffer, + &BufferSize, + SizeNeeded, + "Target1", + "Alias", + "DiscoveryDomain", + 3, + 1); + + iScsiAddPortalGroup(&Buffer, + &BufferSize, + SizeNeeded, + 1); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x12345678, + "SymbolicName", + 5003, + 0x11223344, + 0, + NULL + ); + + + // + // Target 2, 2 portal groups, 1 portal and 2 portals + // + iScsiAddDiscoveredTarget(&Buffer, + &BufferSize, + SizeNeeded, + "Target2", + NULL, + "DiscoveryDomain", + 3, + 2); + + iScsiAddPortalGroup(&Buffer, + &BufferSize, + SizeNeeded, + 1); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111111, + "SymbolicName", + 5003, + 0x44332211, + 8, + "12345678"); + + iScsiAddPortalGroup(&Buffer, + &BufferSize, + SizeNeeded, + 2); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x12345678, + "SymbolicName1", + 5003, + 0x23, + 8, + "12345678"); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x12345679, + "SymbolicName2", + 5003, + 0x34, + 8, + "12345678"); + + // + // Target 3 + // + iScsiAddDiscoveredTarget(&Buffer, + &BufferSize, + SizeNeeded, + "Target3", + NULL, + NULL, + 3, + 2); + + iScsiAddPortalGroup(&Buffer, + &BufferSize, + SizeNeeded, + 5); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111111, + "SymbolicName1", + 5003, + 0x23, + 0, + NULL); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111113, + "SymbolicName2", + 5003, + 0x23, + 0, + NULL); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111113, + NULL, + 5003, + 0x23, + 0, + NULL); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111114, + NULL, + 5003, + 0x23, + 0, + NULL); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x11111115, + "SymbolicName5", + 5003, + 0x23, + 0, + NULL); + + iScsiAddPortalGroup(&Buffer, + &BufferSize, + SizeNeeded, + 2); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x12345678, + "SymbolicName1", + 5003, + 0x23, + 0, + NULL); + + status = iScsiAddPortalToGroup(&Buffer, + &BufferSize, + SizeNeeded, + 0x12345679, + "SymbolicName2", + 5003, + 0x23, + 0, + NULL); + + return(status); +} + +UCHAR +iSpReadTCPConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + Read the iScsi Initiator Instance TCP configuration into the OS buffer. + +Arguments: + + AdapterExtension - miniport drivers storage + Buffer - Used to store all the information of a paticular initiator + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_TCPIPConfig TCPConfigData; + UCHAR status; + + + TCPConfigData = (PMSiSCSI_TCPIPConfig)Buffer; + RtlZeroMemory(TCPConfigData, sizeof(MSiSCSI_TCPIPConfig)); + + RtlCopyMemory(TCPConfigData, + &(AdapterExtension->TCPConfigData), + sizeof(MSiSCSI_TCPIPConfig)); + + if (TCPConfigData->IpAddress.TextAddress[0] == 0) + { + TCPConfigData->IpAddress.TextAddress[0] = 256 * sizeof(WCHAR); + } + + if (TCPConfigData->DefaultGateway.TextAddress[0] == 0) + { + TCPConfigData->DefaultGateway.TextAddress[0] = 256 * sizeof(WCHAR); + } + + if (TCPConfigData->SubnetMask.TextAddress[0] == 0) + { + TCPConfigData->SubnetMask.TextAddress[0] = 256 * sizeof(WCHAR); + } + + if (TCPConfigData->PreferredDNSServer.TextAddress[0] == 0) + { + TCPConfigData->PreferredDNSServer.TextAddress[0] = 256 * sizeof(WCHAR); + } + + if (TCPConfigData->AlternateDNSServer.TextAddress[0] == 0) + { + TCPConfigData->AlternateDNSServer.TextAddress[0] = 256 * sizeof(WCHAR); + } + + return SRB_STATUS_SUCCESS; +} + + +UCHAR +iSpReadNICConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + Read the iScsi Initiator Instance statistics information into the OS buffer. + +Arguments: + + AdapterExtension - miniport drivers storage + Buffer - Used to store all the information of a paticular initiator + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_NICConfig NICConfigData; + UCHAR status; + + + NICConfigData = (PMSiSCSI_NICConfig)Buffer; + + RtlZeroMemory(NICConfigData, sizeof(MSiSCSI_NICConfig)); + + // Link Speed + NICConfigData->LinkSpeed = 100000000; + + // Link State + NICConfigData->LinkState = ISCSI_NIC_LINKSTATE_CONNECTED; + + NICConfigData->MaxFrameSize = 65536; + + // Ethernet MAC Address + NICConfigData->MacAddress[0] = 0x31; + NICConfigData->MacAddress[1] = 0x32; + NICConfigData->MacAddress[2] = 0x33; + NICConfigData->MacAddress[3] = 0x34; + NICConfigData->MacAddress[4] = 0x35; + NICConfigData->MacAddress[5] = 0x36; + + status = SRB_STATUS_SUCCESS; + return status; +} + + +UCHAR +iSpSetTCPConfigInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN ULONG BufferSize, + IN PUCHAR Buffer + ) +/*++ + +Routine Description: + + Sets the content in the Buffer to the drivers adapterExtension + +Arguments: + + AdapterExtension - iScsi miniport driver's adapter data storage. + + BufferSize - Specifies the size in bytes of the buffer at Buffer. + + Buffer - Points to a buffer that contains new values for the instance. + +Return Value: + + UCHAR - SRB Status for this request + +--*/ +{ + PMSiSCSI_TCPIPConfig PTCPConfigBuffer; + PISCSI_IP_Address iScsiIPAddress; + PISCSI_IP_Address destiScsiIPAddress; + PUCHAR currentIpData; + ULONG sizeNeeded; + ULONG inx; + UCHAR status = SRB_STATUS_SUCCESS; + + PTCPConfigBuffer = (PMSiSCSI_TCPIPConfig)Buffer; + + sizeNeeded = FIELD_OFFSET(MSiSCSI_TCPIPConfig, IpAddress); + + if ((Buffer == NULL) || (BufferSize < sizeNeeded)) { + + return SRB_STATUS_ERROR; + } + + RtlZeroMemory(&(AdapterExtension->TCPConfigData), + sizeof(MSiSCSI_TCPIPConfig)); + + AdapterExtension->TCPConfigData.UseLinkLocalAddress = + PTCPConfigBuffer->UseLinkLocalAddress; + + AdapterExtension->TCPConfigData.EnableDHCP = + PTCPConfigBuffer->EnableDHCP; + + BufferSize -= sizeNeeded; + + iScsiIPAddress = &(PTCPConfigBuffer->IpAddress); + + destiScsiIPAddress = &(AdapterExtension->TCPConfigData.IpAddress); + + // + // 5 is the number of ISCSI_IP_Address entries + // in MSiSCSI_TCPIPConfig structure + // + inx = 0; + while (inx < 5) { + + status = SRB_STATUS_SUCCESS; + + sizeNeeded = FIELD_OFFSET(ISCSI_IP_Address, TextAddress) + sizeof(WCHAR); + + if (BufferSize < sizeNeeded) { + + status = SRB_STATUS_ERROR; + } else { + + sizeNeeded += iScsiIPAddress->TextAddress[0]; + + if (BufferSize < sizeNeeded) { + status = SRB_STATUS_ERROR; + } + } + + if (status == SRB_STATUS_SUCCESS) { + + BufferSize -= sizeNeeded; + + destiScsiIPAddress->Type = iScsiIPAddress->Type; + + iScsiIPAddress->TextAddress[0] = + MAX_ISCSI_TEXT_ADDRESS_LEN * sizeof(WCHAR); + + switch (iScsiIPAddress->Type) { + case ISCSI_IP_ADDRESS_TEXT: + { + RtlCopyMemory(&(destiScsiIPAddress->TextAddress[1]), + &(iScsiIPAddress->TextAddress[1]), + iScsiIPAddress->TextAddress[0]); + + break; + } + + case ISCSI_IP_ADDRESS_IPV4: + { + destiScsiIPAddress->IpV4Address = + iScsiIPAddress->IpV4Address; + + break; + } + + case ISCSI_IP_ADDRESS_IPV6: + { + RtlCopyMemory(destiScsiIPAddress->IpV6Address, + iScsiIPAddress->IpV6Address, + sizeof(iScsiIPAddress->IpV6Address)); + + destiScsiIPAddress->IpV6FlowInfo = + iScsiIPAddress->IpV6FlowInfo; + + destiScsiIPAddress->IpV6ScopeId = + iScsiIPAddress->IpV6ScopeId; + + break; + } + + default: + { + status = SRB_STATUS_ERROR; + return(status); + break; + } + } + + iScsiIPAddress = (PISCSI_IP_Address) ((PUCHAR)(iScsiIPAddress) + + ((sizeNeeded + 3) & ~3)); + + destiScsiIPAddress++; + + inx++; + + } else { + + break; + } + } + + return status; +} + +UCHAR +iScsiSetWmiDataBlock( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG BufferSize, + IN PUCHAR Buffer + ) +/*+++ + +Routine Description: + + This routine is called to set a WMI data block. + +--*/ +{ + PISCSI_ADAPTER_EXTENSION adapterExtension; + ULONG sizeNeeded = 0; + PSCSI_WMI_REQUEST_BLOCK srb; + UCHAR status; + + DebugPrint((iScsiPrtDebugTrace, + "SetWmiDataBlock : GuidIndex - %x\n", + GuidIndex)); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "SetWmiDataBlock : GuidIndex - %x\n", + GuidIndex); + + adapterExtension = (PISCSI_ADAPTER_EXTENSION) Context; + srb = (PSCSI_WMI_REQUEST_BLOCK) DispatchContext->UserContext; + + switch (GuidIndex) + { + case iScsiDiscoveryConfigGuid_INDEX: + { + status = iScsiSetDiscoveryConfig(adapterExtension, + BufferSize, + Buffer); + sizeNeeded = 0; + break; + } + + case iScsi_TCPConfig_GUID_Index: + { + status = iSpSetTCPConfigInfo(adapterExtension, BufferSize, Buffer); + break; + } + + default: + { + status = SRB_STATUS_ERROR; + break; + } + } + + iSpCompleteWmiRequest(adapterExtension, srb, DispatchContext, status, sizeNeeded); + + // + // return SRB_STATUS_PENDING since the request has either already been + // completed in iSpCompleteWmiRequest or the status is really + // SRB_STATUS_PENDING. This implies that the iScsiWmiSrb routine + // may not touch the srb since it is already completed. + // + return SRB_STATUS_PENDING; + +} + +UCHAR iScsiPerformPing( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + PISCSI_IP_Address IpAddress, + ULONG RequestCount, + ULONG RequestSize, + ULONG Timeout, + ISDSC_STATUS *Status, + ULONG *ResponseCount +) +{ + // + // Here is where the HBA should do the ping operations. Note that + // this code doesn't pend, but your code should pend as the ping + // operation could be lengthy. + // + *Status = STATUS_SUCCESS; + *ResponseCount = RequestCount; + + return(SRB_STATUS_SUCCESS); +} + +UCHAR iSCSIValidateIPAddress( + PISCSI_IP_Address IpAddress, + ULONG BufferSize + ) +{ + ULONG sizeUsed; + UCHAR srbStatus; + + sizeUsed = (FIELD_OFFSET(ISCSI_IP_Address, + TextAddress) + + sizeof(USHORT)); + + if (BufferSize >= sizeUsed) + { + BufferSize -= sizeUsed; + sizeUsed = IpAddress->TextAddress[0]; + + if (BufferSize >= sizeUsed) + { + srbStatus = SRB_STATUS_SUCCESS; + } else { + srbStatus = SRB_STATUS_INVALID_REQUEST; + } + } else { + srbStatus = SRB_STATUS_INVALID_REQUEST; + } + + return(srbStatus); +} + +UCHAR iSCSIPerformPingOperation( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ULONG InBufferSize, + ULONG OutBufferSize, + ULONG *SizeNeeded, + PUCHAR Buffer + ) +{ + ULONG requestCount; + ULONG requestSize; + ULONG timeout; + ULONG responseCount; + PISCSI_IP_Address ipAddress; + UCHAR srbStatus; + PPingIPAddress_OUT pingOut; + PPingIPAddress_IN pingIn; + ISDSC_STATUS status; + + + // + // Make sure there is enough room in out buffer + // + *SizeNeeded = sizeof(PingIPAddress_OUT); + + if (OutBufferSize >= *SizeNeeded) + { + if (InBufferSize > FIELD_OFFSET(PingIPAddress_IN, + Address)) + { + pingIn = (PPingIPAddress_IN)Buffer; + requestCount = pingIn->RequestCount; + requestSize = pingIn->RequestSize; + timeout = pingIn->Timeout; + ipAddress = &pingIn->Address; + + srbStatus = iSCSIValidateIPAddress(ipAddress, + InBufferSize - + FIELD_OFFSET(PingIPAddress_IN, + Address) + ); + + if (srbStatus == SRB_STATUS_SUCCESS) + { + srbStatus = iScsiPerformPing(AdapterExtension, + ipAddress, + requestCount, + requestSize, + timeout, + &status, + &responseCount); + + // + // return the results of the ping + // + pingOut = (PPingIPAddress_OUT)Buffer; + pingOut->Status = status; + pingOut->ResponsesReceived = responseCount; + } + + } else { + // + // Input buffer is not correct size + // + srbStatus = SRB_STATUS_INVALID_REQUEST; + } + + } else { + srbStatus = SRB_STATUS_DATA_OVERRUN; + } + + return(srbStatus); +} + + +UCHAR +iScsiExecuteWmiMethod( + IN PVOID Context, + IN PSCSIWMI_REQUEST_CONTEXT DispatchContext, + IN ULONG GuidIndex, + IN ULONG InstanceIndex, + IN ULONG MethodId, + IN ULONG InBufferSize, + IN ULONG OutBufferSize, + IN OUT PUCHAR Buffer + ) +/*+++ + +Routine Description: + + This routine is called to execute a WMI method. + The methods here include Login, Logout, SendTargets, etc + +--*/ +{ + PISCSI_ADAPTER_EXTENSION adapterExtension; + PSCSI_WMI_REQUEST_BLOCK srb; + PISCSI_SRB_EXTENSION srbExtension; + ULONG sizeNeeded = 0; + UCHAR status = SRB_STATUS_SUCCESS; + + DebugPrint((iScsiPrtDebugTrace, + "ExecuteWMIMethod : GuidIndex - %x, MethodId - %x\n", + GuidIndex, + MethodId)); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "ExecuteWMIMethod : GuidIndex - %x, MethodId - %x\n", + GuidIndex, + MethodId); + + adapterExtension = (PISCSI_ADAPTER_EXTENSION) Context; + + srb = (PSCSI_WMI_REQUEST_BLOCK) DispatchContext->UserContext; + + srbExtension = (PISCSI_SRB_EXTENSION) srb->SrbExtension; + + // + // Save the input parameters in the SRB extension + // + srbExtension->Buffer = Buffer; + srbExtension->InBufferSize = InBufferSize; + srbExtension->OutBufferSize = OutBufferSize; + + // + // Note that in all the WMI calls, if we are setting the status + // in Buffer (loginTargetOut, logoutTargetOut, etc), we should + // always return SRB_STATUS_SUCCESS. Status field will be set + // to STATUS_SUCCESS if the operation is successful, and will + // be set to the approproate error code if there was an error. + // + switch (GuidIndex) { + case iSCSI_Operations_GUID_Index: { + + DebugPrint((iScsiPrtDebugTrace, + "iSCSI Operations method %d\n", + MethodId)); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "iSCSI Operations method %d\n", + MethodId); + + switch (MethodId) { + case LoginToTarget: { + + PLoginToTarget_IN loginTargetIn; + + sizeNeeded = sizeof(LoginToTarget_OUT); + + if (InBufferSize < sizeof(LoginToTarget_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(LoginToTarget_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + loginTargetIn = (PLoginToTarget_IN) Buffer; + + status = iSpProcessLoginToTarget(adapterExtension, + loginTargetIn, + srb, + InBufferSize); + break; + } + + case LogoutFromTarget: { + + PLogoutFromTarget_IN logoutTargetIn; + + sizeNeeded = sizeof(LogoutFromTarget_OUT); + + if (InBufferSize < sizeof(LogoutFromTarget_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(LogoutFromTarget_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + logoutTargetIn = (PLogoutFromTarget_IN) Buffer; + + status = iSpProcessLogoutFromTarget(adapterExtension, + logoutTargetIn, + srb); + break; + } + + case AddConnectionToSession: { + + PAddConnectionToSession_IN addConnectionIn; + + sizeNeeded = sizeof(AddConnectionToSession_OUT); + + if (InBufferSize < sizeof(AddConnectionToSession_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(AddConnectionToSession_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + addConnectionIn = (PAddConnectionToSession_IN) Buffer; + + status = iSpProcessAddConnectionToSession(adapterExtension, + addConnectionIn, + srb, + InBufferSize); + break; + } + + case RemoveConnectionFromSession: { + + PRemoveConnectionFromSession_IN removeConnectionIn; + + if (InBufferSize < sizeof(RemoveConnectionFromSession_IN)) { + + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(RemoveConnectionFromSession_OUT)) { + + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + removeConnectionIn = (PRemoveConnectionFromSession_IN) Buffer; + + sizeNeeded = sizeof(RemoveConnectionFromSession_OUT); + + status = iSpProcessRemoveConnectionToSession(adapterExtension, + removeConnectionIn, + srb, + InBufferSize); + break; + } + + case SendTargets: { + + PSendTargets_IN sendTargetsIn; + + sizeNeeded = sizeof(SendTargets_OUT); + + if (InBufferSize < sizeof(SendTargets_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(SendTargets_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + sendTargetsIn = (PSendTargets_IN) Buffer; + + status = iSpProcessSendTargets(adapterExtension, + sendTargetsIn, + srb); + + break; + } + + case ScsiInquiry: { + + PScsiInquiry_IN scsiInquiryIn; + + sizeNeeded = sizeof(ScsiInquiry_OUT); + + if (InBufferSize < sizeof(ScsiInquiry_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(ScsiInquiry_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + scsiInquiryIn = (PScsiInquiry_IN) Buffer; + + status = iSpProcessScsiInquiry(adapterExtension, + scsiInquiryIn, + srb); + break; + } + + case ScsiReadCapacity: { + + PScsiReadCapacity_IN scsiReadCapacityIn; + + sizeNeeded = sizeof(ScsiReadCapacity_OUT); + + if (InBufferSize < sizeof(ScsiReadCapacity_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(ScsiReadCapacity_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + scsiReadCapacityIn = (PScsiReadCapacity_IN) Buffer; + + status = iSpProcessScsiReadCapacity(adapterExtension, + scsiReadCapacityIn, + srb); + + break; + } + + case ScsiReportLuns: { + + PScsiReportLuns_IN scsiReportLunsIn; + + sizeNeeded = sizeof(ScsiReportLuns_OUT); + + if (InBufferSize < sizeof(ScsiReportLuns_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(ScsiReportLuns_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + scsiReportLunsIn = (PScsiReportLuns_IN) Buffer; + + status = iSpProcessScsiReportLuns(adapterExtension, + scsiReportLunsIn, + srb); + break; + } + + case SetCHAPSharedSecret: { + + PSetCHAPSharedSecret_IN setCHAPSecretIn; + PSetCHAPSharedSecret_OUT setCHAPSecretOut; + ULONG secretSize; + ULONG bufferSizeNeeded; + + setCHAPSecretOut = (PSetCHAPSharedSecret_OUT) Buffer; + + sizeNeeded = 0; + + RtlZeroMemory(adapterExtension->InitiatorSecret, + sizeof(adapterExtension->InitiatorSecret)); + + adapterExtension->InitiatorSecretLen = 0; + + if (InBufferSize >= FIELD_OFFSET(SetCHAPSharedSecret_IN, + SharedSecret)) { + + setCHAPSecretIn = (PSetCHAPSharedSecret_IN) Buffer; + + secretSize = setCHAPSecretIn->SharedSecretSize; + + if (secretSize == 0) { + + setCHAPSecretOut->Status = STATUS_SUCCESS; + + status = SRB_STATUS_SUCCESS; + + } else if (secretSize > MAX_CHAP_SECRET_LENGTH) { + + setCHAPSecretOut->Status = ISDSC_NON_SPECIFIC_ERROR; + + status = SRB_STATUS_SUCCESS; + + } else { + + bufferSizeNeeded = secretSize + + FIELD_OFFSET(SetCHAPSharedSecret_IN, + SharedSecret); + + if (InBufferSize >= bufferSizeNeeded) { + + RtlCopyMemory(adapterExtension->InitiatorSecret, + setCHAPSecretIn->SharedSecret, + secretSize); + + adapterExtension->InitiatorSecretLen = secretSize; + + status = SRB_STATUS_SUCCESS; + + setCHAPSecretOut->Status = STATUS_SUCCESS; + } else { + + status = SRB_STATUS_INVALID_REQUEST; + + setCHAPSecretOut->Status = ISDSC_NON_SPECIFIC_ERROR; + } + } + + sizeNeeded = sizeof(SetCHAPSharedSecret_OUT); + + } else { + + status = SRB_STATUS_INVALID_REQUEST; + } + + break; + } + + case SetRADIUSSharedSecret: { + + PSetRADIUSSharedSecret_IN setRADIUSSecretIn; + PSetRADIUSSharedSecret_OUT setRADIUSSecretOut; + ULONG secretSize; + ULONG bufferSizeNeeded; + + setRADIUSSecretOut = (PSetRADIUSSharedSecret_OUT) Buffer; + + sizeNeeded = 0; + + RtlZeroMemory(adapterExtension->RadiusSecret, + sizeof(adapterExtension->RadiusSecret)); + + adapterExtension->RadiusSecretLen = 0; + + if (InBufferSize >= FIELD_OFFSET(SetRADIUSSharedSecret_IN, + SharedSecret)) { + + setRADIUSSecretIn = (PSetRADIUSSharedSecret_IN) Buffer; + + secretSize = setRADIUSSecretIn->SharedSecretSize; + + if (secretSize == 0) { + + setRADIUSSecretOut->Status = STATUS_SUCCESS; + + status = SRB_STATUS_SUCCESS; + + } else if (secretSize > MAX_RADIUS_SECRET_LENGTH) { + + setRADIUSSecretOut->Status = ISDSC_NON_SPECIFIC_ERROR; + + status = SRB_STATUS_SUCCESS; + + } else { + + bufferSizeNeeded = secretSize + + FIELD_OFFSET(SetRADIUSSharedSecret_IN, + SharedSecret); + + if (InBufferSize >= bufferSizeNeeded) { + + RtlCopyMemory(adapterExtension->RadiusSecret, + setRADIUSSecretIn->SharedSecret, + secretSize); + + adapterExtension->RadiusSecretLen = secretSize; + + status = SRB_STATUS_SUCCESS; + + setRADIUSSecretOut->Status = STATUS_SUCCESS; + } else { + + status = SRB_STATUS_INVALID_REQUEST; + + setRADIUSSecretOut->Status = ISDSC_NON_SPECIFIC_ERROR; + } + } + + sizeNeeded = sizeof(SetRADIUSSharedSecret_OUT); + + } else { + + status = SRB_STATUS_INVALID_REQUEST; + } + + break; + } + + case RemovePersistentLogin: { + + PRemovePersistentLogin_IN removePersistentLoginIn; + + sizeNeeded = sizeof(RemovePersistentLogin_OUT); + + if (InBufferSize < sizeof(RemovePersistentLogin_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(RemovePersistentLogin_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + removePersistentLoginIn = (PRemovePersistentLogin_IN) Buffer; + + status = iSpRemovePersistentLogin(adapterExtension, + removePersistentLoginIn, + srb); + break; + } + + case AddRADIUSServer: { + + PAddRADIUSServer_IN addRADIUSServerIn; + PAddRADIUSServer_OUT addRADIUSServerOut; + ULONG newServerNameLength; + PISCSI_IP_Address list; + ULONG count; + ULONG updatedCount; + ULONG size; + ULONG inx = 0; + BOOLEAN addressFound = FALSE; + + sizeNeeded = sizeof(AddRADIUSServer_OUT); + + if (InBufferSize < sizeof(AddRADIUSServer_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(AddRADIUSServer_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + addRADIUSServerIn = (PAddRADIUSServer_IN) Buffer; + + addRADIUSServerOut = (PAddRADIUSServer_OUT) Buffer; + + list = adapterExtension->RadiusServerList; + count = adapterExtension->RadiusServerListCount; + + while (inx < count) { + + if (RtlEqualMemory(&(list[inx]), + &(addRADIUSServerIn->RADIUSIPAddress), + sizeof(ISCSI_IP_Address))) { + + addressFound = TRUE; + + status = SRB_STATUS_SUCCESS; + + addRADIUSServerOut->Status = STATUS_SUCCESS; + + break; + } + + inx++; + } + + if (addressFound) { + break; + } + + updatedCount = count + 1; + size = updatedCount * sizeof(ISCSI_IP_Address); + + adapterExtension->RadiusServerList = ExAllocatePoolWithTag(NonPagedPool, + size, + 'vrSR'); + + if (adapterExtension->RadiusServerList != NULL) { + + RtlZeroMemory(adapterExtension->RadiusServerList, + size); + + RtlCopyMemory(adapterExtension->RadiusServerList, + &(addRADIUSServerIn->RADIUSIPAddress), + sizeof(ISCSI_IP_Address)); + + if (count > 0) { + + RtlCopyMemory((adapterExtension->RadiusServerList + 1), + list, + (count * sizeof(ISCSI_IP_Address))); + } + + adapterExtension->RadiusServerListCount = updatedCount; + + if (list != NULL) { + + ExFreePool(list); + } + + status = SRB_STATUS_SUCCESS; + + addRADIUSServerOut->Status = STATUS_SUCCESS; + + } else { + + adapterExtension->RadiusServerList = list; + + status = SRB_STATUS_INVALID_REQUEST; + + addRADIUSServerOut->Status = ISDSC_OUT_OF_RESOURCES; + + } + + break; + } + + case RemoveRADIUSServer: { + + PRemoveRADIUSServer_IN removeRADIUSServerIn; + PRemoveRADIUSServer_OUT removeRADIUSServerOut; + PISCSI_IP_Address removeAddress; + PISCSI_IP_Address list; + ULONG count; + PWCHAR updatedList; + ULONG updatedCount; + ULONG itr; + PISCSI_IP_Address itrList; + BOOLEAN found = FALSE; + ULONG size = 0; + + + sizeNeeded = sizeof(RemoveRADIUSServer_OUT); + + if (InBufferSize < sizeof(RemoveRADIUSServer_IN)) { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + if (OutBufferSize < sizeof(RemoveRADIUSServer_OUT)) { + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + removeRADIUSServerIn = (PRemoveRADIUSServer_IN) Buffer; + + removeRADIUSServerOut = (PRemoveRADIUSServer_OUT) Buffer; + + list = adapterExtension->RadiusServerList; + count = adapterExtension->RadiusServerListCount; + + itr = 0; + itrList = list; + removeAddress = &(removeRADIUSServerIn->RADIUSIPAddress); + while (itr < count) { + + ULONG inx; + + if (itrList->Type == removeAddress->Type) { + + if (itrList->Type == ISCSI_IP_ADDRESS_IPV4) { + if (itrList->IpV4Address == removeAddress->IpV4Address) { + found = TRUE; + } + } + + if (itrList->Type == ISCSI_IP_ADDRESS_IPV6) { + for (inx = 0; inx < 16; inx++) { + if (itrList->IpV6Address[inx] == removeAddress->IpV6Address[inx]) { + found = TRUE; + } else { + found = FALSE; + break; + } + } + } + + if (itrList->Type == ISCSI_IP_ADDRESS_TEXT) { + if (wcscmp(itrList->TextAddress, removeAddress->TextAddress) == 0) { + found = TRUE; + } + } + } + + if (found) + break; + + itr++; + itrList++; + } + + if (found) { + + updatedCount = count - 1; + size = updatedCount * sizeof(ISCSI_IP_Address); + + if (updatedCount > 0) { + + adapterExtension->RadiusServerList = ExAllocatePoolWithTag(NonPagedPool, + size, + 'vrSR'); + + if (adapterExtension->RadiusServerList != NULL) { + + RtlZeroMemory(adapterExtension->RadiusServerList, + size); + + RtlCopyMemory(adapterExtension->RadiusServerList, + list, + (itr * sizeof(ISCSI_IP_Address))); + + itr++; + itrList++; + + if (itr < count) { + + RtlCopyMemory((adapterExtension->RadiusServerList) + (itr - 1), + itrList, + ((count - itr) * sizeof(ISCSI_IP_Address))); + } + + adapterExtension->RadiusServerListCount = updatedCount; + + ExFreePool(list); + + status = SRB_STATUS_SUCCESS; + + removeRADIUSServerOut->Status = STATUS_SUCCESS; + + } else { + + adapterExtension->RadiusServerList = list; + + status = SRB_STATUS_INVALID_REQUEST; + + removeRADIUSServerOut->Status = ISDSC_OUT_OF_RESOURCES; + + } + } else { + + adapterExtension->RadiusServerList = NULL; + + adapterExtension->RadiusServerListCount = updatedCount; + + ExFreePool(list); + + status = SRB_STATUS_SUCCESS; + + removeRADIUSServerOut->Status = STATUS_SUCCESS; + } + + } else { + + removeRADIUSServerOut->Status = ISDSC_NON_SPECIFIC_ERROR; + + status = SRB_STATUS_INVALID_REQUEST; + } + + break; + } + + default: { + + status = SRB_STATUS_INVALID_REQUEST; + + break; + } + } // switch (MethodId) + + break; + } // case iSCSI_Operations_GUID_Index: + + case iScsi_LB_Operations_GUID_Index: { + + DebugPrint((iScsiPrtDebugTrace, + "Set LB policy\n")); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "Set LB policy\n"); + + switch (MethodId) { + case SetLoadBalancePolicy: { + + sizeNeeded = sizeof(SetLoadBalancePolicy_OUT); + + if (OutBufferSize >= sizeNeeded) { + + status = iSpSetLoadBalancePolicy(adapterExtension, + srb, + Buffer, + InBufferSize); + } else { + + DebugPrint((iScsiPrtDebugError, + "Output buffer too small for SetLBPolicy\n")); + + ETWDebugPrint(iScsiLevelError, iScsiFlagWmi, + "Output buffer too small for SetLBPolicy\n"); + + status = SRB_STATUS_DATA_OVERRUN; + } + + break; + } + + default: { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + } + + break; + } // iScsi_LB_Operations_GUID_Index + + case iSCSI_DiscoveryOperationsGuid_INDEX: { + switch (MethodId) + { + case ReportDiscoveredTargets2: + { + status = iScsiReportDiscoveredTargets2(adapterExtension, + OutBufferSize, + &sizeNeeded, + Buffer); + break; + } + + default: { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + } + break; + } // case iSCSI_DiscoveryOperationsGuid_INDEX + + case iScsi_ManagementOperation_GUID_Index: { + switch (MethodId) + { + case PingIPAddress: + { + status = iSCSIPerformPingOperation(adapterExtension, + InBufferSize, + OutBufferSize, + &sizeNeeded, + Buffer); + break; + } + + default: { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + } + break; + } + + case iSCSI_SecurityConfigOperationsGuid_INDEX: + { + switch (MethodId) + { + case SetPresharedKeyForId: + { + status = iScsiSetPresharedKeyForId(adapterExtension, + InBufferSize, + OutBufferSize, + &sizeNeeded, + Buffer); + break; + } + + case SetGroupPresharedKey: + { + status = iScsiSetGroupPresharedKey(adapterExtension, + InBufferSize, + OutBufferSize, + &sizeNeeded, + Buffer); + break; + } + + case SetTunnelModeOuterAddress: + { + status = iScsiSetTunnelModeOuterAddress(adapterExtension, + InBufferSize, + OutBufferSize, + &sizeNeeded, + Buffer); + break; + } + + default: { + status = SRB_STATUS_INVALID_REQUEST; + break; + } + } + break; + } // case iSCSI_SecurityConfigOperationsGuid_INDEX + + default: { + + status = SRB_STATUS_INVALID_REQUEST; + + break; + } + } // switch (GuidIndex) + + // + // Complete the request here if the request is NOT pending + // + if (status != SRB_STATUS_PENDING) { + + iSpCompleteWmiRequest(adapterExtension, + srb, + DispatchContext, + status, + sizeNeeded); + } + + // + // return SRB_STATUS_PENDING since the request has either already been + // completed in iSpCompleteWmiRequest or the status is really + // SRB_STATUS_PENDING. This implies that the iScsiWmiSrb routine + // may not touch the srb since it is already completed. + // + return SRB_STATUS_PENDING; +} + + +ISDSC_STATUS +iSpValidateLoginParameters( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PLoginToTarget_IN LoginTargetIn, + IN ULONG InBufferSize + ) +{ + ULONG sizeNeeded; + ISCSI_AUTH_TYPES authType; + BOOLEAN inputValid; + + + // + // Ensure that the given buffer is large enough to hold + // all login input data + // + sizeNeeded = FIELD_OFFSET(LoginToTarget_IN, Mappings) + + FIELD_OFFSET(ISCSI_TargetMapping, LUNList); + + if (InBufferSize >= sizeNeeded ) { + + sizeNeeded += (LoginTargetIn->Mappings.LUNCount * sizeof(ISCSI_LUNList)) + + LoginTargetIn->KeySize + + LoginTargetIn->UsernameSize + + LoginTargetIn->PasswordSize; + } + + if (InBufferSize < sizeNeeded) { + + DebugPrint((iScsiPrtDebugError, + "Buffer too small for login. Given %d, Needed %d\n", + InBufferSize, sizeNeeded)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Buffer too small for login. Given %d, Needed %d\n", + InBufferSize, sizeNeeded); + + return ISDSC_LOGIN_USER_INFO_BAD; + } + + // + // Validate session type + // + if (LoginTargetIn->SessionType > ISCSI_LOGINTARGET_DATA) { + + DebugPrint((iScsiPrtDebugError, + "Invalid session type %d\n", + LoginTargetIn->SessionType)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid session type %d\n", + LoginTargetIn->SessionType); + + return ISDSC_SESSION_TYPE_NOT_SUPPORTED; + } + + // + // Make sure the size of the username and password, if given, + // are less than or equal to max length + // + if (LoginTargetIn->LoginOptions.InformationSpecified & ISCSI_LOGIN_OPTIONS_AUTH_TYPE) { + authType = LoginTargetIn->LoginOptions.AuthType; + } else { + authType = ISCSI_NO_AUTH_TYPE; + } + + if ((authType == ISCSI_CHAP_AUTH_TYPE) || + (authType == ISCSI_MUTUAL_CHAP_AUTH_TYPE)) { + + // + // A non-zero CHAP Username must be provided for CHAP + // + if ((LoginTargetIn->UsernameSize == 0) || + (LoginTargetIn->UsernameSize > MAX_CHAP_USERNAME_LENGTH)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid username size %d\n", + LoginTargetIn->UsernameSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid username size %d\n", + LoginTargetIn->UsernameSize); + + return ISDSC_INVALID_CHAP_USER_NAME; + } + + // + // If doing CHAP then we need to have the target's chap secret + // + if (((LoginTargetIn->PasswordSize == 0) && !(LoginTargetIn->LoginOptions.LoginFlags & ISCSI_LOGIN_FLAG_USE_RADIUS_RESPONSE))|| + (LoginTargetIn->PasswordSize > MAX_CHAP_SECRET_LENGTH)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid target secret size %d\n", + LoginTargetIn->PasswordSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid target secret size %d\n", + LoginTargetIn->PasswordSize); + + return ISDSC_INVALID_TARGET_CHAP_SECRET; + } + + // + // If we are performing mutual authentication ensure + // that initiator's secret is set, and it is not + // same as the target's secret. + // + if (authType == ISCSI_MUTUAL_CHAP_AUTH_TYPE) { + + PUCHAR userNamePtr; + PUCHAR targetSecret; + ULONG secretLen; + + if (!(LoginTargetIn->LoginOptions.LoginFlags & ISCSI_LOGIN_FLAG_USE_RADIUS_VERIFICATION)) { + + iSpGetUserNameAndPasswordForLogin(LoginTargetIn, + &userNamePtr, + &targetSecret); + + secretLen = AdapterExtension->InitiatorSecretLen; + if ((secretLen == 0) || + ((secretLen == LoginTargetIn->PasswordSize) && + (RtlCompareMemory(AdapterExtension->InitiatorSecret, + targetSecret, + secretLen) == secretLen))) { + + DebugPrint((iScsiPrtDebugError, + "Either no initiator secret is set or it is same as target secret\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagCHAP, + "Either no initiator secret is set or it is same as target secret\n"); + + return ISDSC_INVALID_INITIATOR_CHAP_SECRET; + } + } + } + } else if (authType != ISCSI_NO_AUTH_TYPE) { + + // + // Only chap and mutual chap are supported + // + + DebugPrint((iScsiPrtDebugError, + "Invalid authentication type %d\n", + authType)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid authentication type %d\n", + authType); + + return ISDSC_INVALID_LOGON_AUTH_TYPE; + } + + // + // Check the address type. We currently only support IPv4 and IPv6 + // + if ((LoginTargetIn->TargetPortal.Address.Type != ISCSI_IP_ADDRESS_IPV4) && + (LoginTargetIn->TargetPortal.Address.Type != ISCSI_IP_ADDRESS_IPV6)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid address type %d\n", + LoginTargetIn->TargetPortal.Address.Type)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid address type %d\n", + LoginTargetIn->TargetPortal.Address.Type); + + return ISDSC_ADDRESS_TYPE_NOT_SUPPORTED; + } + + inputValid = TRUE; + + // + // Check if target mappings are valid + // + if ((LoginTargetIn->Mappings.OSBus != -1) && + (LoginTargetIn->Mappings.OSBus >= ISCSI_MAX_BUSES)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid OSBus %x\n", + LoginTargetIn->Mappings.OSBus)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid OSBus %x\n", + LoginTargetIn->Mappings.OSBus); + + inputValid = FALSE; + } + + if ((inputValid == TRUE) && + (LoginTargetIn->Mappings.OSTarget != -1) && + (LoginTargetIn->Mappings.OSTarget >= ISCSI_MAX_TARGETS)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid OSTarget %x\n", + LoginTargetIn->Mappings.OSTarget)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid OSTarget %x\n", + LoginTargetIn->Mappings.OSTarget); + + inputValid = FALSE; + } + + if (inputValid == TRUE) { + + PISCSI_LUNList lunList; + ULONG inx; + + for (inx = 0; inx < LoginTargetIn->Mappings.LUNCount; inx++) { + + lunList = &(LoginTargetIn->Mappings.LUNList[inx]); + + if (lunList->OSLUN >= ISCSI_MAX_LOGICAL_UNITS) { + + DebugPrint((iScsiPrtDebugError, + "Invalid OSLun %x\n", + lunList->OSLUN)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid OSLun %x\n", + lunList->OSLUN); + + inputValid = FALSE; + + break; + } + } + } + + if (inputValid == FALSE) { + return ISDSC_INVALID_TARGET_MAPPING; + } + + return STATUS_SUCCESS; +} + + +ISDSC_STATUS +iSpValidateAddConnectionParameters( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PAddConnectionToSession_IN AddConnectionIn, + IN ULONG InBufferSize + ) +{ + ISDSC_STATUS status = STATUS_SUCCESS; + ULONG sizeNeeded; + ISCSI_AUTH_TYPES authType; + + + // + // Make sure the given buffer is large enough to hold + // all add connection input data. + // + sizeNeeded = FIELD_OFFSET(AddConnectionToSession_IN, Key); + if (sizeNeeded <= InBufferSize) { + + sizeNeeded += AddConnectionIn->KeySize + + AddConnectionIn->UsernameSize + + AddConnectionIn->PasswordSize; + } + + if (sizeNeeded > InBufferSize) { + + DebugPrint((iScsiPrtDebugError, + "Add connection: Size Needed %d, Given %d\n", + sizeNeeded, + InBufferSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Add connection: Size Needed %d, Given %d\n", + sizeNeeded, + InBufferSize); + + return ISDSC_LOGIN_USER_INFO_BAD; + } + + // + // Check the address type. We currently only support IPv4 and IPv6 + // + if ((AddConnectionIn->TargetPortal.Address.Type != ISCSI_IP_ADDRESS_IPV4) && + (AddConnectionIn->TargetPortal.Address.Type != ISCSI_IP_ADDRESS_IPV6)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid address type %d\n", + AddConnectionIn->TargetPortal.Address.Type)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid address type %d\n", + AddConnectionIn->TargetPortal.Address.Type); + + return ISDSC_ADDRESS_TYPE_NOT_SUPPORTED; + } + + // + // Make sure the size of the username and password, if given, + // are less than or equal to max length + // + if (AddConnectionIn->LoginOptions.InformationSpecified & ISCSI_LOGIN_OPTIONS_AUTH_TYPE) { + authType = AddConnectionIn->LoginOptions.AuthType; + } else { + authType = ISCSI_NO_AUTH_TYPE; + } + + if ((authType == ISCSI_CHAP_AUTH_TYPE) || + (authType == ISCSI_MUTUAL_CHAP_AUTH_TYPE)) { + + // + // A non-zero CHAP Username must be provided for CHAP + // + if ((AddConnectionIn->UsernameSize == 0) || + (AddConnectionIn->UsernameSize > MAX_CHAP_USERNAME_LENGTH)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid username size %d\n", + AddConnectionIn->UsernameSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid username size %d\n", + AddConnectionIn->UsernameSize); + + return ISDSC_INVALID_CHAP_USER_NAME; + } + + // + // If doing CHAP then we need to have the target's chap secret + // + if (((AddConnectionIn->PasswordSize == 0) && + !(AddConnectionIn->LoginOptions.LoginFlags & ISCSI_LOGIN_FLAG_USE_RADIUS_RESPONSE)) || + (AddConnectionIn->PasswordSize > MAX_CHAP_SECRET_LENGTH)) { + + DebugPrint((iScsiPrtDebugError, + "Invalid target secret size %d\n", + AddConnectionIn->PasswordSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid target secret size %d\n", + AddConnectionIn->PasswordSize); + + return ISDSC_INVALID_TARGET_CHAP_SECRET; + } + + // + // If we are performing mutual authentication ensure + // that initiator's secret is set, and it is not + // same as the target's secret. + // + if (authType == ISCSI_MUTUAL_CHAP_AUTH_TYPE) { + + PUCHAR userNamePtr; + PUCHAR targetSecret; + ULONG secretLen; + + if (!(AddConnectionIn->LoginOptions.LoginFlags & ISCSI_LOGIN_FLAG_USE_RADIUS_VERIFICATION)) { + + iSpGetUserNameAndPasswordForAddConnection(AddConnectionIn, + &userNamePtr, + &targetSecret); + + secretLen = AdapterExtension->InitiatorSecretLen; + if ((secretLen == 0) || + ((secretLen == AddConnectionIn->PasswordSize) && + (RtlCompareMemory(AdapterExtension->InitiatorSecret, + targetSecret, + secretLen) == secretLen))) { + + DebugPrint((iScsiPrtDebugError, + "Either no initiator secret is set or it is same as target secret\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Either no initiator secret is set or it is same as target secret\n"); + + return ISDSC_INVALID_INITIATOR_CHAP_SECRET; + } + } + } + } else if (authType != ISCSI_NO_AUTH_TYPE) { + + // + // Only chap and mutual chap are supported + // + + DebugPrint((iScsiPrtDebugError, + "Invalid authentication type %d\n", + authType)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "Invalid authentication type %d\n", + authType); + + return ISDSC_INVALID_LOGON_AUTH_TYPE; + } + + return STATUS_SUCCESS; +} + + +ULONGLONG +iSpGetSessionID( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + PISCSI_SESSION IScsiSession, + USHORT UniqueSessionId + ) +/*+++ + +Routine Description: + + This routine returns a unique session id. The session id + is made up of ISID and Microsoft signature byte + +Arguements: + + AdapterExtension - Adapter Extension + + IScsiSession - Pointer to the session + + UniqueSessionId - Two byte session id passed by iSCSI Service + +Return Value: + + 8 Byte SessionId +--*/ +{ + ULONGLONG retVal; + ULONG tempUlong; + + NT_ASSERT((IScsiSession->InitiatorID[0] == 0) && + (IScsiSession->InitiatorID[1] == 0)); + + // + // If SessionId is not initialized, generate a new session id. + // Else, return the saved session id + // + if (IScsiSession->SessionId == 0) { + + tempUlong = (ULONG) UniqueSessionId; + + SetUlongIn2ByteArray((IScsiSession->InitiatorID), tempUlong); + + // + // The unique 64 Bit Session Id is composed this way - + // + // Out of 8 bytes : + // + // Most Significant 4 Bytes are composed of the byte + // ISID_TYPE_ENTERPRISE_NUMBER and the value MSFT_ENTERPRISE_NUMBER + // The Least Significant 4 Bytes are taken from InitiatorSessionID + // + retVal = ((ULONGLONG) ISID_TYPE_ENTERPRISE_NUMBER << 24) | MSFT_ENTERPRISE_NUMBER; + retVal <<= 32; + + retVal |= InterlockedIncrement(&AdapterExtension->InitiatorSessionID); + + IScsiSession->SessionId = retVal; + } else { + + retVal = IScsiSession->SessionId; + } + + DebugPrint((iScsiPrtDebugInfo, + "Session Id returned - 0x%016I64x\n", + retVal)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Session Id returned - 0x%016I64x\n", + retVal); + + return retVal; +} + +UCHAR +iSpReadInitiatorSessionInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PWMI_CONNECTION_LIST ConnectionList, + IN ULONG NumberOfSessions, + OUT PUCHAR Buffer +) +/*++ + +Routine Description: + + Purpose of this routine is to gather initiatorNode information specified in the mof from + the port driver and place them in the incoming Buffer. + +Arguments: + + AdapterExtension - Adpater extension + + SessionListHead - pointer to the first session we have got a remove lock for + + SessionListTail - pointer ot the last session we have got a remove lock for + + InitiatorName - Name of initiator, used to pick out the sessions wanted + + Buffer - Used to store all the information of a paticular initiator + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_InitiatorSessionInfo initiatorSessionInfo; + PISCSI_SessionStaticInfo sessionStaticInfo; + PISCSI_ConnectionStaticInfo connectionStaticInfo; + ULONG sessionIndex; + ULONG connectionIndex; + ULONG inx, skip; + PWMIString WMIformatString; + UCHAR status; + + + status = SRB_STATUS_SUCCESS; + + initiatorSessionInfo = (PMSiSCSI_InitiatorSessionInfo) Buffer; + + initiatorSessionInfo->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + // + // initialize Session count to 0 + // + initiatorSessionInfo->SessionCount=0; + sessionStaticInfo = &(initiatorSessionInfo->SessionsList[0]); + + if (ConnectionList == NULL) { + + DebugPrint((iScsiPrtDebugError, + "Connectionlist NULL in iSpReadInitiatorSessionInfo\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Connectionlist NULL in iSpReadInitiatorSessionInfo\n"); + + return status; + } + + inx = 0; + while (inx < NumberOfSessions) { + + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + + iScsiSession = ConnectionList[inx].ISCSISession; + + if (iScsiSession == NULL) { + + inx++; + + continue; + } + + sessionStaticInfo->UniqueSessionId = iScsiSession->SessionId; + + WMIformatString = (PWMIString)sessionStaticInfo->InitiatoriSCSIName; + WMIformatString->Length = (MAX_INITIATOR_NAME) * sizeof(WCHAR); + RtlCopyMemory(WMIformatString->Buffer, + iScsiSession->InitiatorName, + (MAX_INITIATOR_NAME * sizeof(WCHAR))); + + WMIformatString = (PWMIString)sessionStaticInfo->TargetiSCSIName; + WMIformatString->Length = (MAX_TARGET_NAME) * sizeof(WCHAR); + RtlCopyMemory(WMIformatString->Buffer, + iScsiSession->TargetName, + (MAX_TARGET_NAME * sizeof(WCHAR))); + + sessionStaticInfo->TSID = iScsiSession->TSIH[1] + (iScsiSession->TSIH[0] << 8); + + sessionStaticInfo->ISID[0] = ISID_TYPE_ENTERPRISE_NUMBER; + sessionStaticInfo->ISID[1] = (MSFT_ENTERPRISE_NUMBER & 0xFF0000) >> 16; + sessionStaticInfo->ISID[2] = (MSFT_ENTERPRISE_NUMBER & 0xFF00) >> 8; + sessionStaticInfo->ISID[3] = MSFT_ENTERPRISE_NUMBER & 0xFF; + sessionStaticInfo->ISID[4] = iScsiSession->InitiatorID[0]; + sessionStaticInfo->ISID[5] = iScsiSession->InitiatorID[1]; + + sessionStaticInfo->InitialR2t = iScsiSession->IScsiSessionParams.InitialR2T; + sessionStaticInfo->ImmediateData = iScsiSession->IScsiSessionParams.ImmediateData; + + sessionStaticInfo->Type = iScsiSession->LogonType; + + //False indicates that data PDU Sequences may + //be transferred in any order. True indicates that data PDU + //Sequences must be transferred using continuously increasing offsets, + //except during error recovery. + sessionStaticInfo->DataSequenceInOrder = TRUE; + + //False indicates that data PDUs within Sequences may be in any order. + //True indicates that data PDUs within sequences must be at continuously + //increasing addresses, with no gaps or overlay between PDUs. + sessionStaticInfo->DataPduInOrder = TRUE; + + + //The level of error recovery negotiated between the initiator and the target. + //Higher numbers represent more detailed recovery schemes. + sessionStaticInfo->ErrorRecoveryLevel = (UCHAR) iScsiSession->IScsiSessionParams.ErrorRecoveryLevel; + + sessionStaticInfo->MaxOutstandingR2t = 1; + + //The maximum length supported for unsolicited data + //sent within this session, in units of 512 bytes. + sessionStaticInfo->FirstBurstLength = iScsiSession->IScsiSessionParams.FirstBurstLength; + + //The maximum length supported for unsolicited data + //sent within this session, in units of 512 bytes. + sessionStaticInfo->MaxBurstLength = iScsiSession->IScsiSessionParams.MaxBurstLength; + + //The maximum number of connections that will be + //allowed within this session + sessionStaticInfo->MaxConnections = iScsiSession->IScsiSessionParams.MaxConnections; + + // + // initialize connection count for this session to 0 + // + sessionStaticInfo->ConnectionCount = 0; + + connectionStaticInfo = &(sessionStaticInfo->ConnectionsList[0]); + + for (connectionIndex = 0; + connectionIndex < ConnectionList[inx].Count; + connectionIndex++) + { + + iScsiConnection = ConnectionList[inx].ISCSIConnection[connectionIndex]; + if (iScsiConnection != NULL) { + + ULONG socket; + + connectionStaticInfo->UniqueConnectionId = iScsiConnection->UniqueConnectionID; + connectionStaticInfo->CID = iScsiConnection->ConnectionID[1] + + (iScsiConnection->ConnectionID[0] << 8); + + connectionStaticInfo->HeaderIntegrity = + (UCHAR) iScsiConnection->IScsiConnectionParams.HeaderDigest; + + connectionStaticInfo->DataIntegrity = + (UCHAR) iScsiConnection->IScsiConnectionParams.DataDigest; + + // + // The maximum data payload size supported for command + // or data PDUs within this session, in units of 512 bytes. + // + connectionStaticInfo->MaxRecvDataSegmentLength = + iScsiConnection->IScsiConnectionParams.MaxRecvDataLength; + + connectionStaticInfo->AuthType = iScsiConnection->AuthType; + + + //login - The TCP connection has been established, but a valid iScsi + // login response with the final bit set has not been sent or received. + //full - A valid iScsi login response with the final bit set + // has been sent or received. + //logout - A valid iScsi logout command has been sent or received, but + // the TCP connection has not yet been closed. + connectionStaticInfo->State = iScsiConnection->CurrentProtocolState; + //NOTE: CurrentProtocol enum is different then State enum !?!?!?! + + + //The transport protocol over which this connection instance is running. + connectionStaticInfo->Protocol = TCP; //not saved in deviceExtension yet + + //The Local Inet address used by this connection instance + iSpCopyIPAddress(&connectionStaticInfo->LocalAddr, + &iScsiConnection->LocalIPAddress, + &socket); + + // + // Local TCP port is stored in host byte order in LocalIPAddress. + // Convert that to network byte order here. + // + connectionStaticInfo->LocalPort = htons(socket); + + connectionStaticInfo->LocalAddr.TextAddress[0] = MAX_ISCSI_TEXT_ADDRESS_LEN*sizeof(WCHAR); + + + //The Remote Inet address used by this connection instance + + iSpCopyIPAddress(&connectionStaticInfo->RemoteAddr, + &iScsiConnection->TargetIPAddress, + &connectionStaticInfo->RemotePort); + + connectionStaticInfo->RemoteAddr.TextAddress[0] = MAX_ISCSI_TEXT_ADDRESS_LEN*sizeof(WCHAR); + + connectionStaticInfo->EstimatedThroughput = iScsiConnection->EstimatedThroughput.QuadPart; + + connectionStaticInfo->MaxDatagramSize = iScsiConnection->MaxDatagramSize; + + //increment the connectionStaticInfo pointer to the next 4 byte alligned address; + (PUCHAR) connectionStaticInfo += ((sizeof(ISCSI_ConnectionStaticInfo)+7) & ~7); + + //The number of TCP connections that currently belong to this session + sessionStaticInfo->ConnectionCount ++; + } + } + + // + // Advance to next place to write session information + // + skip = FIELD_OFFSET(ISCSI_SessionStaticInfo, + ConnectionsList) + + (ConnectionList[inx].Count * + ((sizeof(ISCSI_ConnectionStaticInfo)+7) & ~7)); + + skip = (skip +7) & ~7; + + (PUCHAR)sessionStaticInfo += skip; + + initiatorSessionInfo->SessionCount++; + + inx++; + } + + return status; +} + +UCHAR +iSpReadConnStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PISCSI_CONNECTION IScsiConnection, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + Read the iScsi connection statistics information into the OS buffer. + +Arguments: + + IScsiConnection - iScsi miniport driver's connection data storage. + + Buffer - Buffer to hold iScsi connection statistics information. + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_ConnectionStatistics ConnectStatistics; + PWMIString WMIformatString; + UCHAR status; + + + status = SRB_STATUS_SUCCESS; + + ConnectStatistics = (PMSiSCSI_ConnectionStatistics)Buffer; + RtlZeroMemory(Buffer, sizeof(MSiSCSI_ConnectionStatistics)); + + WMIformatString = (PWMIString)ConnectStatistics->iSCSIName; + WMIformatString->Length = MAX_INITIATOR_NAME * sizeof(WCHAR); + RtlCopyMemory(WMIformatString->Buffer, + IScsiConnection->ISCSISession->InitiatorName, + (MAX_INITIATOR_NAME * sizeof(WCHAR))); + + ConnectStatistics->CID = (IScsiConnection->ConnectionID[0] << 8) + + IScsiConnection->ConnectionID[1]; + + // + // A uniquely generated session ID used only internally. + // Do not mix this with ISID. + // + if (IScsiConnection->ISCSISession != NULL) { + + ConnectStatistics->USID = IScsiConnection->ISCSISession->SessionId; + } + + ConnectStatistics->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + ConnectStatistics->BytesSent = IScsiConnection->BytesSent; + ConnectStatistics->BytesReceived = IScsiConnection->BytesReceived; + ConnectStatistics->PDUCommandsSent = IScsiConnection->PDUCommandsSent; + ConnectStatistics->PDUResponsesReceived = IScsiConnection->PDUResponsesReceived; + + return status; +} + +UCHAR +iSpReadSessionStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PISCSI_SESSION IScsiSession, + IN PWMI_CONNECTION_LIST ConnectionList, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + Read the iScsi session statistics information into the OS buffer. + +Arguments: + + IScsiSession - iScsi miniport driver's session data storage. + + Buffer - Buffer to hold iScsi connection statistics information. + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_SessionStatistics SessionStatistics; + PISCSI_CONNECTION connection; + PWMIString WMIformatString; + ULONG inx; + UCHAR status; + + + status = SRB_STATUS_SUCCESS; + + SessionStatistics = (PMSiSCSI_SessionStatistics)Buffer; + RtlZeroMemory(Buffer, sizeof(MSiSCSI_SessionStatistics)); + + if (IScsiSession != NULL) { + + WMIformatString = (PWMIString)SessionStatistics->iSCSIName; + WMIformatString->Length = MAX_INITIATOR_NAME * sizeof(WCHAR); + RtlCopyMemory(WMIformatString->Buffer, + IScsiSession->InitiatorName, + (MAX_INITIATOR_NAME * sizeof(WCHAR))); + + SessionStatistics->USID = IScsiSession->SessionId; + + SessionStatistics->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + SessionStatistics->BytesSent = 0; + SessionStatistics->BytesReceived = 0; + SessionStatistics->PDUCommandsSent = 0; + SessionStatistics->PDUResponsesReceived = 0; + + inx = 0; + while (inx < ConnectionList->Count) + { + PISCSI_CONNECTION iScsiConnection; + + iScsiConnection = ConnectionList->ISCSIConnection[inx]; + if (iScsiConnection != NULL) { + SessionStatistics->BytesSent += iScsiConnection->BytesSent; + SessionStatistics->BytesReceived += iScsiConnection->BytesReceived; + SessionStatistics->PDUCommandsSent += iScsiConnection->PDUCommandsSent; + SessionStatistics->PDUResponsesReceived += iScsiConnection->PDUResponsesReceived; + } + + inx++; + } + } + + return status; +} + +UCHAR +iSpReadInitiatorLoginStatistics( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PWMI_CONNECTION_LIST ConnectionList, + IN ULONG NumberOfSessions, + OUT PUCHAR Buffer + ) +/*++ + +Routine Description: + + Read the iScsi Initiator Node statistics information into the OS buffer. + +Arguments: + + SessionListHead - pointer to the first session we have got a remove lock for + + SessionListTail - pointer ot the last session we have got a remove lock for + + InitiatorName - Name of initiator, used to pick out the sessions wanted + + Buffer - Used to store all the information of a paticular initiator + +Return Value: + + Status - SRB Status for this request + +--*/ +{ + PMSiSCSI_InitiatorLoginStatistics initiatorLoginStatistics; + UCHAR status; + ULONG inx; + + + status = SRB_STATUS_SUCCESS; + + initiatorLoginStatistics = (PMSiSCSI_InitiatorLoginStatistics) Buffer; + + initiatorLoginStatistics->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + initiatorLoginStatistics->LogoutNormals = AdapterExtension->LogoutNormals; + + initiatorLoginStatistics->LogoutOtherCodes = AdapterExtension->LogoutOtherRsps; + + inx = 0; + while (inx < NumberOfSessions) { + + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + + if ((ConnectionList != NULL) && (ConnectionList[inx].Count > 0)) { + + iScsiConnection = ConnectionList[inx].ISCSIConnection[0]; + NT_ASSERT(iScsiConnection != NULL); + + iScsiSession = iScsiConnection->ISCSISession; + + if (iScsiSession != NULL) { + + initiatorLoginStatistics->LoginAcceptRsps += iScsiSession->LoginAcceptRsps; + + initiatorLoginStatistics->LoginOtherFailRsps += iScsiSession->LoginOtherFailRsps; + + initiatorLoginStatistics->LoginRedirectRsps += iScsiSession->LoginRedirectRsps; + + initiatorLoginStatistics->LoginAuthFailRsps += iScsiSession->LoginAuthFailRsps; + + initiatorLoginStatistics->LoginAuthenticateFails += iScsiSession->LoginAuthenticateFails; + + initiatorLoginStatistics->LoginNegotiateFails += iScsiSession->LoginNegotiateFails; + + initiatorLoginStatistics->LoginFailures += iScsiSession->LoginFailures; + + } + } + + inx++; + } + + return status; +} + + +VOID +iSpCompleteWmiRequest( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + PSCSI_WMI_REQUEST_BLOCK Srb, + PSCSIWMI_REQUEST_CONTEXT DispatchContext, + UCHAR Status, + ULONG SizeNeeded + ) +/*+++ + +Routine Description: + + This routine calls iScsiPrt to notify that a request + is completed. + +Arguements: + + AdapterExtension - Adapater extension for the initiator + + Srb - The request being completed + + DispatchContext - WMI request context. + + Status - SRB Status for this request + + SizeNeeded - Buffer size needed to process this request + +Return Value: + + None +--*/ +{ + // + // Complete the request if the status is NOT pending or NOT + // already completed within the callback. + // + if (Status != SRB_STATUS_PENDING) { + + // + // Request completed successfully or there was an error. + // + ScsiPortWmiPostProcess(DispatchContext, + Status, + SizeNeeded); + + Srb->SrbStatus = ScsiPortWmiGetReturnStatus(DispatchContext); + Srb->DataTransferLength = ScsiPortWmiGetReturnSize(DispatchContext); + + // + // Adapter ready for next request. + // + ScsiPortNotification(RequestComplete, AdapterExtension, Srb); + } +} + +UCHAR +iSpGetDynamicConnectionInstanceName( + IN PISCSI_CONNECTION IScsiConnection, + IN OUT PWMIString InstanceName + ) +/*++ + +Routine Description: + + Get the instanceName for the specified connection. Instance names are formatted as + follows: "targetname_#:#" where the first # is the display session ID, and the second + # is the CID. + +Arguments: + + IScsiConnection - iScsi miniport driver's connection data storage. + + InstanceName - A pointer to WMIString, on return contains the dynamic instance name for the + specified connection. + +Return Value: + + UCHAR - SRB Status for this request + +--*/ +{ + + WCHAR uniCodeString[MAX_UNICODE_STR_LENGTH]; + PWCHAR currentPos; + ULONG InstanceNameLength; + PWMIString WMIformatString; + KIRQL oldIrql; + ULONG displaySessionID; + PISCSI_SESSION sessionListHead; + PISCSI_SESSION sessionListTail; + PISCSI_SESSION iScsiSession; + PISCSI_ADAPTER_EXTENSION adapterExtension; + NTSTATUS rtlStatus; + UCHAR status; + USHORT convertedLength; + USHORT maxBufferSize; + UCHAR numString[MAX_UNICODE_STR_LENGTH]; + + + status = SRB_STATUS_SUCCESS; + + RtlZeroMemory(uniCodeString, sizeof(uniCodeString)); + + maxBufferSize = sizeof(uniCodeString) / sizeof(WCHAR); + + rtlStatus = RtlStringCchCopyNW(uniCodeString, maxBufferSize, + IScsiConnection->ISCSISession->TargetName, + wcslen(IScsiConnection->ISCSISession->TargetName)); + if (rtlStatus != STATUS_SUCCESS) { + return SRB_STATUS_ERROR; + } + + convertedLength = (USHORT)wcslen(IScsiConnection->ISCSISession->TargetName); + + (PUCHAR)currentPos = (PUCHAR)uniCodeString + convertedLength*sizeof(WCHAR); + + maxBufferSize = (sizeof(uniCodeString)/sizeof(WCHAR)) - convertedLength; + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + rtlStatus = RtlStringCchCopyW(currentPos, maxBufferSize, L"_"); + if (rtlStatus != STATUS_SUCCESS) { + return SRB_STATUS_ERROR; + } + (PUCHAR)currentPos += sizeof(WCHAR); + maxBufferSize--; + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + displaySessionID = IScsiConnection->ISCSISession->DisplaySessionID; + + RtlZeroMemory(numString, sizeof(numString)); + (void) _itoa_s(displaySessionID, numString, _countof(numString), 10); + + convertedLength = AsciiStringToWideCharString( + currentPos, + numString, + maxBufferSize); + + // + // AsciiStringToWideCharString returns the number of characters including the terminating NULL. + // + maxBufferSize = maxBufferSize - (convertedLength - 1); + (PUCHAR)currentPos += ((convertedLength -1 )* sizeof(WCHAR)); + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + rtlStatus = RtlStringCchCopyW(currentPos, maxBufferSize, L":"); + if (rtlStatus != STATUS_SUCCESS) { + return SRB_STATUS_ERROR; + } + (PUCHAR)currentPos += sizeof(WCHAR); + maxBufferSize--; + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + RtlZeroMemory(numString, sizeof(numString)); + (void) _itoa_s((IScsiConnection->ConnectionID[0]<<8) + IScsiConnection->ConnectionID[1], numString, _countof(numString), 10); + convertedLength = AsciiStringToWideCharString(currentPos, + numString, + (USHORT)maxBufferSize); + + // + // AsciiStringToWideCharString returns the number of characters including the terminating NULL. + // + (PUCHAR)currentPos += ((convertedLength - 1)* sizeof(WCHAR)); + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + InstanceNameLength = (ULONG)((PUCHAR)currentPos - (PUCHAR)uniCodeString); + + InstanceName->Length = (USHORT)InstanceNameLength; + + RtlStringCchCopyW(InstanceName->Buffer, InstanceName->Length, uniCodeString); + + return status; + +} + +UCHAR +iSpGetDynamicSessionInstanceName( + IN PISCSI_SESSION IScsiSession, + IN OUT PWMIString InstanceName + ) +/*++ + +Routine Description: + + Get the instanceName for the specified session. Instance names are formatted as + follows: "targetname_#" where the # is the display session ID + +Arguments: + + IScsiSession - iScsi miniport driver's session data storage. + + InstanceName - A pointer to WMIString, on return contains the dynamic instance name for the + specified connection. + +Return Value: + + UCHAR - SRB Status for this request + +--*/ +{ + + WCHAR uniCodeString[MAX_UNICODE_STR_LENGTH + 1]; + PWCHAR currentPos; + ULONG InstanceNameLength; + PWMIString WMIformatString; + KIRQL oldIrql; + ULONG displaySessionID; + PISCSI_SESSION sessionListHead; + PISCSI_SESSION sessionListTail; + PISCSI_SESSION iScsiSession; + PISCSI_ADAPTER_EXTENSION adapterExtension; + NTSTATUS rtlStatus; + UCHAR status = SRB_STATUS_SUCCESS; + USHORT convertedLength; + USHORT maxBufferSize; + UCHAR numString[MAX_UNICODE_STR_LENGTH]; + + + RtlZeroMemory(uniCodeString, sizeof(uniCodeString)); + + convertedLength = (USHORT) wcslen(IScsiSession->TargetName); + + rtlStatus = RtlStringCchCopyNW(uniCodeString, MAX_UNICODE_STR_LENGTH, + IScsiSession->TargetName, + convertedLength); + + if (rtlStatus != STATUS_SUCCESS) { + return SRB_STATUS_ERROR; + } + + (PUCHAR)currentPos = (PUCHAR)uniCodeString + convertedLength*sizeof(WCHAR); + + maxBufferSize = (sizeof(uniCodeString)/sizeof(WCHAR)) - convertedLength; + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + rtlStatus = RtlStringCchCopyW(currentPos, maxBufferSize, L"_"); + if (rtlStatus != STATUS_SUCCESS) { + return SRB_STATUS_ERROR; + } + (PUCHAR)currentPos += sizeof(WCHAR); + maxBufferSize--; + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + + displaySessionID = IScsiSession->DisplaySessionID; + + RtlZeroMemory(numString, sizeof(numString)); + (void) _itoa_s(displaySessionID, numString, _countof(numString), 10); + convertedLength = AsciiStringToWideCharString(currentPos, + numString, + maxBufferSize); + + // + // AsciiStringToWideCharString returns the number of characters including the terminating NULL. + // + (PUCHAR)currentPos += ((convertedLength -1) * sizeof(WCHAR)); + + if (currentPos > uniCodeString + sizeof(uniCodeString)/sizeof(WCHAR)) { + return SRB_STATUS_ERROR; + } + + InstanceNameLength = (ULONG)((PUCHAR)currentPos - (PUCHAR)uniCodeString); + + if(InstanceNameLength > MAX_UNICODE_STR_LENGTH) + { + status = SRB_STATUS_ERROR; + } else { + + rtlStatus = RtlStringCchCopyNW( + InstanceName->Buffer, + MAX_UNICODE_STR_LENGTH, + uniCodeString, + InstanceNameLength); + + if(NT_SUCCESS(rtlStatus) == FALSE) + { + status = SRB_STATUS_ERROR; + } else { + status = SRB_STATUS_SUCCESS; + } + } + + if(status != SRB_STATUS_SUCCESS) + { + InstanceName->Length = 0; + } else { + InstanceName->Length = (USHORT)InstanceNameLength; + } + + return status; +} + + +VOID +iScsiFireAdapterEvent( + PISCSI_ADAPTER_EXTENSION AdapterExtension, + ISCSI_ADAPTER_EVENT_CODE EventCode + ) +{ + ScsiPortWmiFireAdapterEvent(AdapterExtension, + &iScsiAdapterEventGuid, + 0, + sizeof(ULONG), + &EventCode); +} + + +UCHAR +iSpQueryLBPolicy( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN OUT PULONG InstanceLengthArray, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWMI_CONNECTION_LIST connectionList; + ULONG size, sessionInx; + ULONG numberOfSessions, numberOfConnections; + UCHAR status = SRB_STATUS_SUCCESS;; + + + *SizeNeeded = 0; + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections); + + // + // Determine the size of buffer needed to return LB policy settings + // for all the sessions on this adapter. + // + + // + // First account for the fixed part of MSiSCSI_Supported_LB_Policies + // + size = FIELD_OFFSET(MSiSCSI_QueryLBPolicy, + LoadBalancePolicies); + + if (connectionList == NULL) { + + if (BufferAvail >= size) { + PMSiSCSI_QueryLBPolicy queryLBPolicy; + + queryLBPolicy = (PMSiSCSI_QueryLBPolicy) Buffer; + queryLBPolicy->UniqueAdapterId = (ULONGLONG) AdapterExtension; + queryLBPolicy->SessionCount = 0; + *SizeNeeded = size; + + return SRB_STATUS_SUCCESS; + } else { + + *SizeNeeded = size; + + return SRB_STATUS_SUCCESS; + } + } + + // + // Loop over all sessions and account for the space needed for each + // session plus all of the connections within each session + // + sessionInx = 0; + while (sessionInx < numberOfSessions) { + + // + // Since the session structure needs to be 8 bytes aligned, we + // pad out to 8 bytes + // + size = (size + 7) & ~7; + + // + // Add the fixed size needed for the session structure + // + size += FIELD_OFFSET(ISCSI_Supported_LB_Policies, + iSCSI_Paths); + + // + // Account for the size of all connection structures, being + // sure that the connection structure is padded out to 8 bytes + // in order to maintain 8 byte alignment + // + size += connectionList[sessionInx].Count * + ((sizeof(ISCSI_Path) + 7) & ~7); + + sessionInx++; + } + + *SizeNeeded = size; + + if (size <= BufferAvail) { + + // + // There is enough space to build the LB policy info data + // for all the sessions on this adapter. + // + RtlZeroMemory(Buffer, size); + + status = iSpReadLBPolicyInfo(AdapterExtension, + connectionList, + numberOfSessions, + (PMSiSCSI_QueryLBPolicy) Buffer); + + } else { + + // + // There is not enough space to build the LB policy info data + // for all the sessions on this adapter. + // + status = SRB_STATUS_DATA_OVERRUN; + } + + *InstanceLengthArray = *SizeNeeded; + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + + return status; +} + +UCHAR +iSpReadLBPolicyInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PWMI_CONNECTION_LIST ConnectionList, + IN ULONG NumberOfSessions, + OUT PMSiSCSI_QueryLBPolicy QueryLBPolicy + ) +{ + PISCSI_Supported_LB_Policies supportedLBPolicies; + PISCSI_Path iScsiPath; + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + ULONG sessionInx; + ULONG connectionInx; + ULONG skip; + UCHAR status = SRB_STATUS_SUCCESS; + + QueryLBPolicy->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + QueryLBPolicy->SessionCount = 0; + + supportedLBPolicies = QueryLBPolicy->LoadBalancePolicies; + + sessionInx = 0; + while (sessionInx < NumberOfSessions) { + + iScsiSession = ConnectionList[sessionInx].ISCSISession; + + supportedLBPolicies->UniqueSessionId = iScsiSession->SessionId; + + supportedLBPolicies->LoadBalancePolicy = iScsiSession->LoadBalancePolicy; + + supportedLBPolicies->iSCSI_PathCount = 0; + connectionInx = 0; + while (connectionInx < ConnectionList[sessionInx].Count) { + + iScsiConnection = ConnectionList[sessionInx].ISCSIConnection[connectionInx]; + if (iScsiConnection != NULL) { + + iScsiPath = &(supportedLBPolicies->iSCSI_Paths[connectionInx]); + + iScsiPath->UniqueConnectionId = (ULONGLONG) iScsiConnection->UniqueConnectionID; + + iScsiPath->EstimatedLinkSpeed = iScsiConnection->EstimatedThroughput.QuadPart; + + iScsiPath->PathWeight = iScsiConnection->PathWeight; + + iScsiPath->PrimaryPath = iScsiConnection->CurrentPathStatus; + + iScsiPath->TCPOffLoadAvailable = 0; + + switch (iScsiConnection->ConnectionState) { + case ConnectionStateConnected : { + iScsiPath->ConnectionStatus = CONNECTION_STATE_CONNECTED; + break; + } + + case ConnectionStateDisconnected : + case ConnectionStateStopping: { + iScsiPath->ConnectionStatus = CONNECTION_STATE_DISCONNECTED; + break; + } + + case ConnectionStateConnecting : { + iScsiPath->ConnectionStatus = CONNECTION_STATE_RECONNECTING; + break; + } + + default : { + iScsiPath->ConnectionStatus = CONNECTION_STATE_DISCONNECTED; + break; + } + } + + supportedLBPolicies->iSCSI_PathCount++; + } + + connectionInx++; + } + + // + // Advance to next place to write session information + // + skip = FIELD_OFFSET(ISCSI_Supported_LB_Policies, iSCSI_Paths) + + (ConnectionList[sessionInx].Count * ((sizeof(ISCSI_Path) + 7) & ~7)); + + skip = (skip + 7) & ~7; + + (PUCHAR)supportedLBPolicies += skip; + + QueryLBPolicy->SessionCount++; + + sessionInx++; + } + + return status; +} + +UCHAR +iSpSetLoadBalancePolicy( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PSCSI_WMI_REQUEST_BLOCK Srb, + IN PUCHAR Buffer, + IN ULONG InBufferSize + ) +{ + PSetLoadBalancePolicy_IN setLBPolicyIN; + PSetLoadBalancePolicy_OUT setLBPolicyOUT; + PISCSI_Supported_LB_Policies supportedLBPolicy; + PISCSI_SESSION iScsiSession; + PPERSISTENT_TARGET_LB_POLICY LBPolicy = NULL; + PLB_POLICY_DATA LBPolicyData; + ULONG iScsiStatus; + ULONG inx; + BOOLEAN persistLBPolicy = FALSE; + KIRQL oldIrql; + NTSTATUS ntStatus; + + setLBPolicyIN = (PSetLoadBalancePolicy_IN) Buffer; + + setLBPolicyOUT = (PSetLoadBalancePolicy_OUT) Buffer; + + iScsiStatus = iSpValidateLoadBalancePolicy(setLBPolicyIN, + InBufferSize); + if (iScsiStatus != STATUS_SUCCESS) { + + setLBPolicyOUT->Status = iScsiStatus; + + return SRB_STATUS_SUCCESS; + } + + supportedLBPolicy = &(setLBPolicyIN->LoadBalancePolicies); + + iScsiSession = iSpGetIScsiSession(AdapterExtension, + supportedLBPolicy->UniqueSessionId, + Srb); + if (iScsiSession == NULL) { + + DebugPrint((iScsiPrtDebugWarning, + "Invalid session id given %I64x for SetLBPolicy\n", + supportedLBPolicy->UniqueSessionId)); + + ETWDebugPrint(iScsiLevelWarning, + iScsiFlagWmi, + "Invalid session id given %I64x for SetLBPolicy\n", + supportedLBPolicy->UniqueSessionId); + + setLBPolicyOUT->Status = ISDSC_INVALID_SESSION_ID; + + return SRB_STATUS_SUCCESS; + } + + KeAcquireSpinLock(&iScsiSession->SessionLock, &oldIrql); + + iScsiStatus = iSpValidateConnectionIds(iScsiSession, supportedLBPolicy); + + if (iScsiStatus == STATUS_SUCCESS) { + + switch (supportedLBPolicy->LoadBalancePolicy) { + case MSiSCSI_LB_FAILOVER: { + + iScsiStatus = iSpSetLBFailOverOnly(iScsiSession, + supportedLBPolicy); + + break; + } + + case MSiSCSI_LB_DYN_LEAST_QUEUE_DEPTH: + case MSiSCSI_LB_WEIGHTED_PATHS: { + + iScsiStatus = iSpSetLB_LQD_WP(iScsiSession, supportedLBPolicy); + + break; + } + + case MSiSCSI_LB_ROUND_ROBIN: + case MSiSCSI_LB_ROUND_ROBIN_WITH_SUBSET: { + + iScsiStatus = iSpSetLBRoundRobinSubset(iScsiSession, + supportedLBPolicy); + + break; + } + + default: { + + // + // Should never get here since the input policy has already + // been validated in iSpValidateLoadBalancePolicy. + // + iScsiStatus = ISDSC_INVALID_LOAD_BALANCE_POLICY; + } + } + } + + // + // Check if we need to persist the new LB policy + // + if ((iScsiStatus == STATUS_SUCCESS) && + (wcslen(iScsiSession->TargetKeyNameSuffix) > 0)) { + + ULONG sizeNeeded = 0; + ULONG tempUlong; + BOOLEAN overFlow = TRUE; + + if (ULongMult(sizeof(LB_POLICY_DATA), + (iScsiSession->NumberOfConnections - 1), + &tempUlong) == S_OK) { + + if (ULongAdd(sizeof(PERSISTENT_TARGET_LB_POLICY), + tempUlong, &sizeNeeded) == S_OK) { + + overFlow = FALSE; + } + } + + // + // This is a persistent target. Need to save the new LB policy + // in the registry for this persistent target. + // + if (!overFlow) { + + LBPolicy = iSpAllocatePool(NonPagedPool, + sizeNeeded, + ISCSI_TAG_LB_POLICY); + if (LBPolicy != NULL) { + + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + + persistLBPolicy = TRUE; + + RtlStringCchCopyW(LBPolicy->TargetKeyName, + MAX_TARGET_NAME + TARGET_KEYNAME_SUFFIX_SIZE + 1, + iScsiSession->TargetName); + + RtlStringCchCatW(LBPolicy->TargetKeyName, + MAX_TARGET_NAME + TARGET_KEYNAME_SUFFIX_SIZE + 1, + iScsiSession->TargetKeyNameSuffix); + + LBPolicy->LoadBalancePolicy = supportedLBPolicy->LoadBalancePolicy; + + LBPolicy->ConnectionCount = iScsiSession->NumberOfConnections; + + for (inx = 0; inx < supportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(supportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + LBPolicyData = &(LBPolicy->PolicyData[inx]); + + LBPolicyData->ConnectionNumber = iScsiConnection->ConnectionNumber; + + LBPolicyData->PathWeight = iScsiConnection->PathWeight; + + LBPolicyData->PrimaryPath = iScsiConnection->CurrentPathStatus; + } + } else { + + DebugPrint((iScsiPrtDebugError, + "Failed to allocate memory for persisting LB policy\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to allocate memory for persisting LB policy\n"); + } + } + } + + KeReleaseSpinLock(&iScsiSession->SessionLock, oldIrql); + + if (persistLBPolicy) { + + NT_ASSERT(LBPolicy != NULL); + + ntStatus = iSpPersisteLBPolicy(AdapterExtension, LBPolicy); + + if(NT_SUCCESS(ntStatus) == FALSE) + { + iScsiStatus = ISDSC_FAILURE_TO_PERSIST_LB_POLICY; + } + + ExFreePool(LBPolicy); + } + + // + // Release the reference taken in iSpGetIScsiSession + // + IoReleaseRemoveLock(iScsiSession->RemoveLock, REMOVELOCK_TAG(Srb)); + + setLBPolicyOUT->Status = iScsiStatus; + + return SRB_STATUS_SUCCESS; +} + +ULONG +iSpValidateLoadBalancePolicy( + IN PSetLoadBalancePolicy_IN SetLBPolicyIN, + IN ULONG InBufferSize + ) +{ + PISCSI_Supported_LB_Policies supportedLBPolicy; + PISCSI_Path iScsiPath0; + PISCSI_Path iScsiPath1; + ULONG iScsiStatus = STATUS_SUCCESS; + ULONG sizeNeeded; + ULONG inx, jnx; + KIRQL oldIrql; + + sizeNeeded = FIELD_OFFSET(ISCSI_Supported_LB_Policies, iSCSI_Paths); + if (InBufferSize < sizeNeeded) { + + DebugPrint((iScsiPrtDebugError, + "Input buffer too small for SetLBPolicy. Expected %d, Given %d\n", + sizeNeeded, + InBufferSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Input buffer too small for SetLBPolicy. Expected %d, Given %d\n", + sizeNeeded, + InBufferSize); + + return ISDSC_BUFFER_TOO_SMALL; + } + + supportedLBPolicy = &(SetLBPolicyIN->LoadBalancePolicies); + + sizeNeeded += supportedLBPolicy->iSCSI_PathCount * + ((sizeof(ISCSI_Path) + 7) & ~7); + + if (InBufferSize < sizeNeeded) { + + DebugPrint((iScsiPrtDebugError, + "Input buffer too small for SetLBPolicy. Expected %d, Given %d\n", + sizeNeeded, + InBufferSize)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Input buffer too small for SetLBPolicy. Expected %d, Given %d\n", + sizeNeeded, + InBufferSize); + + return ISDSC_BUFFER_TOO_SMALL; + } + + if ((supportedLBPolicy->LoadBalancePolicy < MSiSCSI_LB_FAILOVER) || + (supportedLBPolicy->LoadBalancePolicy > MSiSCSI_LB_WEIGHTED_PATHS)){ + + DebugPrint((iScsiPrtDebugError, + "Invalid Load Balance Policy %d\n", + supportedLBPolicy->LoadBalancePolicy)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Invalid Load Balance Policy %d\n", + supportedLBPolicy->LoadBalancePolicy); + + return ISDSC_INVALID_LOAD_BALANCE_POLICY; + } + + // + // Make sure user did not provide duplicate path ids + // + for (inx = 0; inx < supportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath0 = &(supportedLBPolicy->iSCSI_Paths[inx]); + + for (jnx = 0; jnx < supportedLBPolicy->iSCSI_PathCount; jnx++) { + + iScsiPath1 = &(supportedLBPolicy->iSCSI_Paths[jnx]); + + if ((inx != jnx) && + (iScsiPath0->UniqueConnectionId == iScsiPath1->UniqueConnectionId)) { + + DebugPrint((iScsiPrtDebugError, + "Duplicate path ids at %d and %d\n", + inx, + jnx)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Duplicate path ids at %d and %d\n", + inx, + jnx); + + iScsiStatus = ISDSC_DUPLICATE_PATH_SPECIFIED; + + break; + } + + jnx++; + } + + if (iScsiStatus != STATUS_SUCCESS) { + break; + } + + inx++; + } + + return iScsiStatus; +} + +ULONG +iSpValidateConnectionIds( + IN PISCSI_SESSION IScsiSession, + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + PLIST_ENTRY connectionEntry; + ULONG iScsiStatus = STATUS_SUCCESS; + ULONG inx; + BOOLEAN found; + + if (IScsiSession->NumberOfConnections != SupportedLBPolicy->iSCSI_PathCount) { + + DebugPrint((iScsiPrtDebugError, + "Number of connections %d does not match path count %d\n", + IScsiSession->NumberOfConnections, + SupportedLBPolicy->iSCSI_PathCount)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Number of connections %d does not match path count %d\n", + IScsiSession->NumberOfConnections, + SupportedLBPolicy->iSCSI_PathCount); + + return ISDSC_PATH_COUNT_MISMATCH; + } + + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + found = FALSE; + + connectionEntry = IScsiSession->ConnectionList.Flink; + while (connectionEntry != &IScsiSession->ConnectionList) { + + iScsiConnection = CONTAINING_RECORD(connectionEntry, + ISCSI_CONNECTION, + NextConnection); + + connectionEntry = connectionEntry->Flink; + + // + // Path Id that is returned in QueryLBPolicy is UniqueConnectionID + // + if (iScsiConnection->UniqueConnectionID == iScsiPath->UniqueConnectionId) { + + // + // Set the pointer to iscsi_connection in UniqueConnectionId. This will + // be used in SetLBPolicy routine to set the load balance policy. + // + iScsiPath->UniqueConnectionId = (ULONGLONG) iScsiConnection; + + found = TRUE; + + break; + } + } + + if (!found) { + + DebugPrint((iScsiPrtDebugError, + "Path Id %I64x not found\n", + iScsiPath->UniqueConnectionId)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Path Id %I64x not found\n", + iScsiPath->UniqueConnectionId); + + iScsiStatus = ISDSC_INVALID_PATH_ID; + + break; + } + } + + return iScsiStatus; +} + +ULONG +iSpSetLBFailOverOnly( + IN PISCSI_SESSION IScsiSession, + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + ULONG inx; + ULONG iScsiStatus = STATUS_SUCCESS; + BOOLEAN activeFound = FALSE; + + // + // Save the current value of path status. + // + iSpSavePrimaryPath(SupportedLBPolicy); + + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + if (iScsiPath->PrimaryPath) { + + // + // Primary path specified. Make sure one hasn't been + // specified earlier since only one primary path is + // allowed for FailOverOnly policy. + // + if (!activeFound) { + + DebugPrint((iScsiPrtDebugInfo, + "%p specified as Primary Path\n", + iScsiConnection)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "%p specified as Primary Path\n", + iScsiConnection); + + iScsiConnection->CurrentPathStatus = TRUE; + + activeFound = TRUE; + } else { + + DebugPrint((iScsiPrtDebugError, + "Multiple primary paths given for LBFailOverOnly\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Multiple primary paths given for LBFailOverOnly\n"); + + iScsiStatus = ISDSC_MULTIPLE_PRIMARY_PATHS_SPECIFIED; + } + } else { + + // + // This is a standby path + // + iScsiConnection->CurrentPathStatus = FALSE; + } + } + + if (!activeFound) { + + DebugPrint((iScsiPrtDebugError, + "No active path given for FO Only\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "No active path given for FO Only\n"); + + iScsiStatus = ISDSC_NO_PRIMARY_PATH_SPECIFIED; + } + + if (NT_SUCCESS(iScsiStatus)) { + + DebugPrint((iScsiPrtDebugInfo, + "FailOverOnly set successfully for %p\n", + IScsiSession)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "FailOverOnly set successfully for %p\n", + IScsiSession); + + IScsiSession->LoadBalancePolicy = LB_FAIL_OVER_ONLY; + } else { + + // + // Failed to set user given LB settings. Restore the value of + // path status from the saved value. + // + iSpRestorePrimaryPath(SupportedLBPolicy); + } + + return iScsiStatus; +} + +ULONG +iSpSetLB_LQD_WP( + IN PISCSI_SESSION IScsiSession, + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + ULONG inx; + + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + iScsiConnection->CurrentPathStatus = TRUE; + + if (SupportedLBPolicy->LoadBalancePolicy == LB_LEAST_WEIGHT_PATH) { + iScsiConnection->PathWeight = iScsiPath->PathWeight; + } + } + + IScsiSession->LoadBalancePolicy = SupportedLBPolicy->LoadBalancePolicy; + + return STATUS_SUCCESS; +} + +ULONG +iSpSetLBRoundRobinSubset( + IN PISCSI_SESSION IScsiSession, + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + ULONG iScsiStatus = STATUS_SUCCESS; + ULONG inx; + BOOLEAN activeFound = FALSE; + + // + // Save the current value of path status. + // + iSpSavePrimaryPath(SupportedLBPolicy); + + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + if (iScsiPath->PrimaryPath) { + + iScsiConnection->CurrentPathStatus = TRUE; + + activeFound = TRUE; + } else { + + iScsiConnection->CurrentPathStatus = FALSE; + } + } + + if (!activeFound) { + + DebugPrint((iScsiPrtDebugError, + "No active path given for Round Robin.\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "No active path given for Round Robin.\n"); + + iScsiStatus = ISDSC_NO_PRIMARY_PATH_SPECIFIED; + } + + if (NT_SUCCESS(iScsiStatus)) { + + DebugPrint((iScsiPrtDebugInfo, + "Successfully set LB policy\n")); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagWmi, + "Successfully set LB policy\n"); + + IScsiSession->LoadBalancePolicy = SupportedLBPolicy->LoadBalancePolicy; + } else { + + // + // Failed to set user given LB settings. Restore the value of + // path status from the saved value. + // + iSpRestorePrimaryPath(SupportedLBPolicy); + } + + return iScsiStatus; +} + +FORCEINLINE +iSpSavePrimaryPath( + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + ULONG inx; + + // + // Save the current LB policy settings before setting new values. + // In case the update fails, we'll restore the old LB settings. + // + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + iScsiConnection->PrevPathStatus = iScsiConnection->CurrentPathStatus; + } +} + +FORCEINLINE +iSpRestorePrimaryPath( + IN PISCSI_Supported_LB_Policies SupportedLBPolicy + ) +/*+++ + + Note: This routine should be called with IScsiSession->SessionLock held + +--*/ +{ + PISCSI_Path iScsiPath; + PISCSI_CONNECTION iScsiConnection; + ULONG inx; + + // + // Restore the LB settings from the saved value. + // + for (inx = 0; inx < SupportedLBPolicy->iSCSI_PathCount; inx++) { + + iScsiPath = &(SupportedLBPolicy->iSCSI_Paths[inx]); + + iScsiConnection = (PISCSI_CONNECTION) iScsiPath->UniqueConnectionId; + + iScsiConnection->CurrentPathStatus = iScsiConnection->PrevPathStatus; + } +} + + +VOID +iSpLogError( + IN PDEVICE_OBJECT DeviceObject, + _In_reads_bytes_opt_(ErrorDataSize) PUCHAR ErrorData, + IN ULONG ErrorDataSize, + _In_opt_ PWSTR TargetName, + IN ULONG ErrorCode + ) +/*+++ + +Routine Description : + + This routine will build a WMI event for the MSiSCSI_Eventlog class + and then fire it. The WMI eventlog consumer provider has classes + that intercept the WMI event and will redirect it to the system + eventlog. + +Arguements: + + DeviceObject is the device object of the adapter + + ErrorData is the data to be placed in the additional data field of + the eventlog + + ErrorDataSize is the number of bytes of additional data + + TargetName is the name of the target + + ErrorCode is the iSCSI eventlog error code (see iscsilog.h) + +Return Value: + +--*/ +{ + PMSiSCSI_Eventlog eventLog; + PUCHAR dumpData; + ULONG totalSize; + ULONG dumpDataSize; + ULONG targetNameSize; + NTSTATUS status; + GUID eventLogGUID = MSiSCSI_EventlogGuid; + + if (TargetName != NULL) { + targetNameSize = wcslen(TargetName) * sizeof(WCHAR); + } else { + targetNameSize = 0; + } + + totalSize = sizeof(MSiSCSI_Eventlog) + + ErrorDataSize + + targetNameSize; + + // + // Allocate memory for MSiSCSI_Eventlog object + // + + + if (eventLog != NULL) { + dumpDataSize = totalSize - FIELD_OFFSET(MSiSCSI_Eventlog, + AdditionalData); + eventLog->Type = ErrorCode; + eventLog->LogToEventlog = 1; + + dumpData = eventLog->AdditionalData; + + // + // Copy the entire error data followed by the target name if given. + // + if ((ErrorData != NULL) && (ErrorDataSize > 0)) { + RtlCopyMemory(dumpData, ErrorData, ErrorDataSize); + dumpData += ErrorDataSize; + } + + if (targetNameSize > 0) { + RtlCopyMemory(dumpData, TargetName, targetNameSize); + } + + eventLog->Size = dumpDataSize; + + // + // Fire the WMI event using eventLogGUID GUID, and + // Free the memory allocated for MSiSCSI_Eventlog object. + // + + } +} + + + +UCHAR +iSpBuildBootInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PULONG InstanceLength, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + UCHAR status; + ULONG size; + + size = sizeof(MSiSCSI_BootInformation); + + if (BufferAvail >= size) { + PMSiSCSI_BootInformation bootInfo; + + bootInfo = (PMSiSCSI_BootInformation)Buffer; + + bootInfo->SharedSecretLength = AdapterExtension->BootSecretLength; + RtlCopyMemory(bootInfo->SharedSecret, AdapterExtension->BootSecret, 255); + RtlCopyMemory(bootInfo->NodeName, + AdapterExtension->BootNodeName, + MAX_INITIATOR_NAME); + *SizeNeeded = size; + + status = SRB_STATUS_SUCCESS; + + } else { + + *SizeNeeded = size; + + status = SRB_STATUS_DATA_OVERRUN; + } + + *InstanceLength = *SizeNeeded; + + return status; +} + +UCHAR +iSpBuildRedirectTargetInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PULONG InstanceLength, + IN ULONG BufferAvail, + OUT PUCHAR Buffer, + OUT PULONG SizeNeeded + ) +{ + PWMI_CONNECTION_LIST connectionList; + ULONG size, sessionInx; + ULONG numberOfSessions, numberOfConnections; + UCHAR status; + + + connectionList = iSpGetConnectionList(AdapterExtension, + &numberOfSessions, + &numberOfConnections); + + DebugPrint((iScsiPrtDebugInfo, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Number of Sessions %d, Number of Connections %d\n", + numberOfSessions, + numberOfConnections); + + // + // determine the size of buffer needed to build all of the session + // and connection data structures + // + + // + // Account for the fixed part of the iScsiInitiatorSessionInfo + // + size = FIELD_OFFSET(MSiSCSI_RedirectPortalInfoClass, RedirectSessionList); + + if (connectionList == NULL) { + + if (BufferAvail >= size) + { + PMSiSCSI_RedirectPortalInfoClass redirectPortalInfo; + + redirectPortalInfo = (PMSiSCSI_RedirectPortalInfoClass)Buffer; + + redirectPortalInfo->UniqueAdapterId = (ULONGLONG) AdapterExtension; + redirectPortalInfo->SessionCount = 0; + *SizeNeeded = size; + + status = SRB_STATUS_SUCCESS; + } else { + + *SizeNeeded = size; + + status = SRB_STATUS_DATA_OVERRUN; + } + + *InstanceLength = *SizeNeeded; + + return status; + } + + // + // Loop over all sessions and account for the space needed for each + // session plus all of the connections within each session + // + sessionInx = 0; + while (sessionInx < numberOfSessions) { + + // + // Since the session structure needs to be 8 bytes aligned, we + // pad out to 8 bytes + // + size = (size + 7) & ~7; + + // + // Add the fixed size needed for the session structure + // + size += FIELD_OFFSET(ISCSI_RedirectSessionInfo, + RedirectPortalList); + + // + // Account for the size of all connection structures, being + // sure that the connection structure is padded out to 8 bytes + // in order to maintain 8 byte alignment + // + size += connectionList[sessionInx].Count * + ((sizeof(ISCSI_RedirectPortalInfo) + 7) & ~7); + + sessionInx++; + } + + *SizeNeeded = size; + if (size <= BufferAvail) + { + // + // If we do have enough space to build the session info data + // structures then we do so + // + RtlZeroMemory(Buffer, size); + + status = iSpReadRedirectTargetPortalInfo(AdapterExtension, + connectionList, + numberOfSessions, + Buffer); + + } else { + // + // If there is not enough space to build the session info data + // structures then return this error + // + status = SRB_STATUS_DATA_OVERRUN; + } + + iSpReleaseConnectionReferences(connectionList, + numberOfSessions); + + + return status; +} + +UCHAR +iSpReadRedirectTargetPortalInfo( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PWMI_CONNECTION_LIST ConnectionList, + IN ULONG NumberOfSessions, + IN PUCHAR Buffer + ) +{ + PISCSI_RedirectPortalInfo redirectPortalInfo; + PISCSI_RedirectSessionInfo redirectSessionInfo; + PMSiSCSI_RedirectPortalInfoClass redirectPortalInfoClass; + ULONG sessionIndex; + ULONG connectionIndex; + ULONG inx, skip; + PWMIString WMIformatString; + UCHAR status = SRB_STATUS_SUCCESS; + + + if (ConnectionList == NULL) { + + DebugPrint((iScsiPrtDebugError, + "Connectionlist NULL in iSpReadInitiatorSessionInfo\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Connectionlist NULL in iSpReadInitiatorSessionInfo\n"); + + return status; + } + + redirectPortalInfoClass = (PMSiSCSI_RedirectPortalInfoClass) Buffer; + + redirectPortalInfoClass->UniqueAdapterId = (ULONGLONG) AdapterExtension; + + // + // initialize Session count to 0 + // + redirectPortalInfoClass->SessionCount = 0; + + redirectSessionInfo = redirectPortalInfoClass->RedirectSessionList; + + inx = 0; + while (inx < NumberOfSessions) { + + PISCSI_SESSION iScsiSession; + PISCSI_CONNECTION iScsiConnection; + + iScsiSession = ConnectionList[inx].ISCSISession; + + if (iScsiSession == NULL) { + + inx++; + + continue; + } + + redirectSessionInfo->UniqueSessionId = iScsiSession->SessionId; + + redirectSessionInfo->TargetPortalGroupTag = iScsiSession->TargetPortalGroupTag; + + redirectSessionInfo->ConnectionCount = 0; + + redirectPortalInfo = redirectSessionInfo->RedirectPortalList; + + for (connectionIndex = 0; + connectionIndex < ConnectionList[inx].Count; + connectionIndex++) + { + + iScsiConnection = ConnectionList[inx].ISCSIConnection[connectionIndex]; + if (iScsiConnection != NULL) { + + redirectPortalInfo->UniqueConnectionId = iScsiConnection->UniqueConnectionID; + + iSpCopyIPAddress(&redirectPortalInfo->OriginalIPAddr, + &iScsiConnection->PermanentTargetIPAddress, + &redirectPortalInfo->OriginalPort); + + redirectPortalInfo->OriginalIPAddr.TextAddress[0] = MAX_ISCSI_TEXT_ADDRESS_LEN*sizeof(WCHAR); + + redirectPortalInfo->Redirected = iScsiConnection->TargetMoved; + + if (iScsiConnection->TargetMoved) { + + iSpCopyIPAddress(&redirectPortalInfo->RedirectedIPAddr, + &iScsiConnection->TargetIPAddress, + &redirectPortalInfo->RedirectedPort); + + redirectPortalInfo->RedirectedIPAddr.TextAddress[0] = MAX_ISCSI_TEXT_ADDRESS_LEN*sizeof(WCHAR); + + redirectPortalInfo->TemporaryRedirect = iScsiConnection->TargetMoveTemporary; + } + + //increment the connectionStaticInfo pointer to the next 4 byte alligned address; + (PUCHAR) redirectPortalInfo += ((sizeof(ISCSI_RedirectPortalInfo)+7) & ~7); + + //The number of TCP connections that currently belong to this session + redirectSessionInfo->ConnectionCount ++; + } + } + + // + // Advance to next place to write session information + // + skip = FIELD_OFFSET(ISCSI_RedirectSessionInfo, RedirectPortalList) + + (ConnectionList[inx].Count * + ((sizeof(ISCSI_RedirectPortalInfo) + 7) & ~7)); + + skip = (skip + 7) & ~7; + + (PUCHAR) redirectSessionInfo += skip; + + redirectPortalInfoClass->SessionCount++; + + inx++; + } + + return status; +} + +NTSTATUS +iSpFindPersistentTargetKey( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + _In_ PWSTR TargetName, + IN PISCSI_TargetPortal TargetPortal, + IN ULONG PortNumber, + OUT PHANDLE TargetKey, + _Out_writes_opt_ (TargetKeyNameSize) PWCHAR TargetKeyName, OPTIONAL + IN ULONG TargetKeyNameSize + ) +{ + HANDLE persistentTargetsKey = NULL; + HANDLE pnpDriverKey; + NTSTATUS status; + + *TargetKey = NULL; + + status = iSpOpenPnPDriverKey(AdapterExtension->PhysicalDeviceObject, + PERSISTENT_TARGETS, + KEY_ALL_ACCESS, + &pnpDriverKey, + &persistentTargetsKey); + if (NT_SUCCESS(status)) { + + KEY_BASIC_INFORMATION keyInfo[ISCSI_KEY_BASIC_INFO_SIZE]; + ULONG resultSize; + ULONG index; + BOOLEAN found; + + index = 0; + found = FALSE; + + while (!found) { + + resultSize = ISCSI_KEY_BASIC_INFO_SIZE * sizeof(KEY_BASIC_INFORMATION); + + RtlZeroMemory(keyInfo, resultSize); + + // + // Enumerate all the keys under PersistentTargets key + // + status = ZwEnumerateKey(persistentTargetsKey, + index, + KeyBasicInformation, + keyInfo, + resultSize, + &resultSize); + if (NT_SUCCESS(status)) { + + PUCHAR regValue; + HANDLE targetNameKey; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING subKeyName; + WCHAR targetKeyName[512]; + ULONG nameLength; + ULONG targetnameLen; + ULONG regValueSize; + + nameLength = keyInfo->NameLength; + + if (nameLength > ISCSI_KEY_BASIC_INFO_NAME_MAXLEN) { + nameLength = ISCSI_KEY_BASIC_INFO_NAME_MAXLEN; + } + + // + // Find the key which matches the given target name + // + + status = RtlStringCchCopyNW( + targetKeyName, + sizeof(targetKeyName)/sizeof(targetKeyName[0]), + keyInfo->Name, + nameLength); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE) + { + goto NextKey; + } + + targetnameLen = wcslen(TargetName); + + if (!wcsncmp(TargetName, targetKeyName, targetnameLen)) { + + // + // Open LoginTarget under this target key + // + RtlStringCchCatW(targetKeyName, 255, L"\\"); + + RtlStringCchCatW(targetKeyName, 255, LOGIN_TARGET_STR); + + RtlInitUnicodeString(&subKeyName, targetKeyName); + + DebugPrint((iScsiPrtDebugInfo, + "Persistent Target Key %ws\n", + targetKeyName)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Persistent Target Key %ws\n", + targetKeyName); + + RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes(&objectAttributes, + &subKeyName, + (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), + persistentTargetsKey, + (PSECURITY_DESCRIPTOR) NULL); + + status = ZwOpenKey(&targetNameKey, + KEY_ALL_ACCESS, + &objectAttributes); + if (NT_SUCCESS(status)) { + + status = iSpQueryRegistryValue(targetNameKey, LOGIN_TARGET_IN, + ISCSI_TAG_LOGINTARGET_IN, + ®Value, ®ValueSize); + if (NT_SUCCESS(status)) { + PLoginToTarget_IN loginTargetIN; + PISCSI_TargetPortal targetPortal; + + loginTargetIN = (PLoginToTarget_IN) regValue; + + targetPortal = &(loginTargetIN->TargetPortal); + + if ((PortNumber == loginTargetIN->PortNumber) && + (targetPortal->Address.Type != ISCSI_IP_ADDRESS_EMPTY) && + (IsSamePortal(TargetPortal, targetPortal))) { + + found = TRUE; + + // + // Open the TargetName key and return a handle to that + // + status = RtlStringCchCopyNW( + targetKeyName, + sizeof(targetKeyName)/sizeof(targetKeyName[0]), + keyInfo->Name, + nameLength); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == TRUE) + { + RtlInitUnicodeString(&subKeyName, targetKeyName); + + RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes(&objectAttributes, + &subKeyName, + (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), + persistentTargetsKey, + (PSECURITY_DESCRIPTOR) NULL); + + status = ZwOpenKey(TargetKey, + KEY_ALL_ACCESS, + &objectAttributes); + if (NT_SUCCESS(status)) { + + if (TargetKeyName != NULL) { + + NT_ASSERT(TargetKeyNameSize > 0); + + status = RtlStringCchCopyNW( + TargetKeyName, + TargetKeyNameSize, + targetKeyName, + sizeof(targetKeyName)/sizeof(targetKeyName[0])); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE) + { + DebugPrint((iScsiPrtDebugError, + "Failed to copy TargetKeyName %ws\n", + targetKeyName)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to copy TargetKeyName %ws\n", + targetKeyName); + + *TargetKey = NULL; + } + } + } else { + *TargetKey = NULL; + } + } else { + + DebugPrint((iScsiPrtDebugError, + "Failed to copy target name from KeyInfo.\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to copy target name from KeyInfo.\n"); + } + } else { + + DebugPrint((iScsiPrtDebugError, + "Portal mismatch. Port Numbers %x, %x\n", + PortNumber, loginTargetIN->PortNumber)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Portal mismatch. Port Numbers %x, %x\n", + PortNumber, loginTargetIN->PortNumber); + } + + ExFreePool(regValue); + } + + ZwClose(targetNameKey); + } + } + } else if (status == STATUS_NO_MORE_ENTRIES) { + + DebugPrint((iScsiPrtDebugError, + "Enumerated all persistent targets\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Enumerated all persistent targets\n"); + + break; + } else { + + DebugPrint((iScsiPrtDebugError, + "ZwEnumerateKey failed for persistent targets. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "ZwEnumerateKey failed for persistent targets. Status %x\n", + status); + + break; + } +NextKey: + index++; + } + + iSpClosePnPDriverKey(&pnpDriverKey, &persistentTargetsKey); + } + + return status; +} + +NTSTATUS +iSpDeleteKeyAndSubkeys( + IN HANDLE RootKey + ) +{ + KEY_BASIC_INFORMATION keyInfo[ISCSI_KEY_BASIC_INFO_SIZE]; + NTSTATUS status = STATUS_SUCCESS; + ULONG resultSize; + ULONG index; + BOOLEAN deleted = FALSE; + + index = 0; + + // + // Enumerate all the keys under the given key and delete each one of them. + // Note that this routine assumes there are no subkeys and the subkeys + // to the Root Key. This routine can only delete a registry tree with + // one sub level below the Root Key. + // + while (status == STATUS_SUCCESS) { + + resultSize = ISCSI_KEY_BASIC_INFO_SIZE * sizeof(KEY_BASIC_INFORMATION); + + RtlZeroMemory(keyInfo, resultSize); + + // + // Enumerate all the keys under the given key + // + status = ZwEnumerateKey(RootKey, + index, + KeyBasicInformation, + keyInfo, + resultSize, + &resultSize); + if (NT_SUCCESS(status)) { + + HANDLE subKeyHandle; + UNICODE_STRING subKey; + WCHAR subKeyName[ISCSI_KEY_BASIC_INFO_NAME_MAXLEN + 1]; // add 1 for null terminator + OBJECT_ATTRIBUTES objectAttributes; + ULONG nameLength; + + deleted = FALSE; + + nameLength = keyInfo->NameLength; + if (nameLength > ISCSI_KEY_BASIC_INFO_NAME_MAXLEN) { + nameLength = ISCSI_KEY_BASIC_INFO_NAME_MAXLEN; + } + + status = RtlStringCchCopyNW( + subKeyName, + sizeof(subKeyName) / sizeof(subKeyName[0]), + keyInfo->Name, + nameLength); + + NT_ASSERT(NT_SUCCESS(status)); + + if(NT_SUCCESS(status) == FALSE) + { + break; + } + + RtlInitUnicodeString(&subKey, subKeyName); + + RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes(&objectAttributes, + &subKey, + (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), + RootKey, + (PSECURITY_DESCRIPTOR) NULL); + + // + // Open this subkey and delete it. + // + status = ZwOpenKey(&subKeyHandle, + KEY_ALL_ACCESS, + &objectAttributes); + if (NT_SUCCESS(status)) { + + // + // Note that there should be no subkeys under this key. Otherwise + // ZwDeleteKey will fail with error STATUS_CANNOT_DELETE. + // + status = ZwDeleteKey(subKeyHandle); + if (NT_SUCCESS(status)) { + + DebugPrint((iScsiPrtDebugInfo, + "Deleted subkey %ws\n", + subKeyName)); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagGeneral, + "Deleted subkey %ws\n", + subKeyName); + + deleted = TRUE; + } else { + + + DebugPrint((iScsiPrtDebugError, + "Failed to delete subkey %ws. Status %x\n", + subKeyName, status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagGeneral, + "Failed to delete subkey %ws. Status %x\n", + subKeyName, status); + } + + ZwClose(subKeyHandle); + + } + } else if (status != STATUS_NO_MORE_ENTRIES) { + + DebugPrint((iScsiPrtDebugError, + "Failed to enumerate subkeys in delete key and subkeys. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagGeneral, + "Failed to enumerate subkeys in delete key and subkeys. Status %x\n", + status); + } + + // + // If the key was successfully deleted do not increment the index since + // the number of keys under RootKey is now lesser by one. + // + if (!deleted) { + index++; + } + } + + if (!NT_SUCCESS(status) && (status == STATUS_NO_MORE_ENTRIES)) { + + // + // This indicates that all the subkeys under Root Key have been + // enumerated and they have been deleted successfully. It is now + // safe to delete the Root Key. + // + status = STATUS_SUCCESS; + + status = ZwDeleteKey(RootKey); + if (!NT_SUCCESS(status)) { + + DebugPrint((iScsiPrtDebugError, + "Failed to delete Root Key. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagGeneral, + "Failed to delete Root Key. Status %x\n", + status); + } else { + + DebugPrint((iScsiPrtDebugTrace, + "Successfully delete all keys and subkeys\n")); + + ETWDebugPrint(iScsiLevelTrace, + iScsiFlagGeneral, + "Successfully delete all keys and subkeys\n"); + } + } else { + + DebugPrint((iScsiPrtDebugError, + "Failed to delete key and all subkeys. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagGeneral, + "Failed to delete key and all subkeys. Status %x\n", + status); + } + + return status; +} + +NTSTATUS +iSpPersisteLBPolicy( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PPERSISTENT_TARGET_LB_POLICY LBPolicy + ) +{ + HANDLE persistentTargetsKey; + HANDLE pnpDriverKey; + PLB_POLICY_DATA LBPolicyData; + ULONG inx; + ULONG lbPolicy; + NTSTATUS status; + + PAGED_CODE(); + + status = iSpOpenPnPDriverKey(AdapterExtension->PhysicalDeviceObject, + PERSISTENT_TARGETS, + KEY_ALL_ACCESS, + &pnpDriverKey, + &persistentTargetsKey); + if (NT_SUCCESS(status)) { + + OBJECT_ATTRIBUTES objectAttributes; + HANDLE subKeyHandle; + HANDLE loginTargetKey; + UNICODE_STRING subKey; + WCHAR subKeyName[32]; + + RtlZeroMemory(subKeyName,sizeof(subKeyName)); + + RtlInitUnicodeString(&subKey, LBPolicy->TargetKeyName); + + RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes(&objectAttributes, + &subKey, + (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), + persistentTargetsKey, + (PSECURITY_DESCRIPTOR) NULL); + + status = ZwOpenKey(&subKeyHandle, + KEY_ALL_ACCESS, + &objectAttributes); + + if (NT_SUCCESS(status)) { + + // + // Save the new Load Balance policy for this target + // + status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, + subKeyHandle, + LOAD_BALANCE_POLICY, + REG_DWORD, + &LBPolicy->LoadBalancePolicy, + sizeof(ISCSI_LOAD_BALANCE_POLICY)); + NT_ASSERT(NT_SUCCESS(status)); + + for (inx = 0; NT_SUCCESS(status) && inx < LBPolicy->ConnectionCount; inx++) { + + // + // Save the PrimaryPath and PathWeight for each connection + // + LBPolicyData = &(LBPolicy->PolicyData[inx]); + + if (LBPolicyData->ConnectionNumber == -1) { + + RtlStringCchCopyW(subKeyName, 32, LOGIN_TARGET_STR); + } else { + + RtlStringCchPrintfW(subKeyName, + ((sizeof(subKeyName) - sizeof(WCHAR))/sizeof(WCHAR)), + L"%ws%d", + ADD_CONNECTION_STR, + LBPolicyData->ConnectionNumber); + } + + DebugPrint((iScsiPrtDebugInfo, + "Will open subkey %ws\n", + subKeyName)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagWmi, + "Will open subkey %ws\n", + subKeyName); + + RtlInitUnicodeString(&subKey, subKeyName); + + RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes(&objectAttributes, + &subKey, + (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), + subKeyHandle, + (PSECURITY_DESCRIPTOR) NULL); + + status = ZwOpenKey(&loginTargetKey, + KEY_ALL_ACCESS, + &objectAttributes); + if (NT_SUCCESS(status)) { + + // + // Save PathWeight and PrimaryPath + // + status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, + loginTargetKey, + PATH_WEIGHT, + REG_DWORD, + &LBPolicyData->PathWeight, + sizeof(ULONG)); + if (!NT_SUCCESS(status)) { + + DebugPrint((iScsiPrtDebugError, + "Failed to save Path Weight. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to save Path Weight. Status %x\n", + status); + } + + status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, + loginTargetKey, + PRIMARY_PATH, + REG_DWORD, + &LBPolicyData->PrimaryPath, + sizeof(ULONG)); + if (!NT_SUCCESS(status)) { + + DebugPrint((iScsiPrtDebugError, + "Failed to save Path Weight. Status %x\n", + status)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to save Path Weight. Status %x\n", + status); + } + + ZwClose(loginTargetKey); + } else { + + DebugPrint((iScsiPrtDebugError, + "Failed to open subkey subKeyName to save LB Policy\n")); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagWmi, + "Failed to open subkey subKeyName to save LB Policy\n"); + } + } + + ZwClose(subKeyHandle); + } + + iSpClosePnPDriverKey(&pnpDriverKey, &persistentTargetsKey); + } + + return status; +} + +NTSTATUS +iSpSetTargetNameSuffix( + IN PISCSI_ADAPTER_EXTENSION AdapterExtension, + IN PLoginToTarget_IN LoginTargetIn + ) +{ + PISCSI_SESSION iScsiSession = NULL; + HANDLE removeTargetKey = NULL; + WCHAR targetName[MAX_TARGET_NAME + 1]; + WCHAR targetKeyName[MAX_TARGET_NAME + TARGET_KEYNAME_SUFFIX_SIZE + 1]; + ULONG bytesToCopy; + KIRQL oldIrql; + NTSTATUS rtlStatus = ERROR_SUCCESS; + + if (LoginTargetIn->SessionType != ISCSI_LOGINTARGET_DATA) { + return STATUS_INVALID_PARAMETER; + } + + RtlZeroMemory(targetKeyName, sizeof(targetKeyName)); + RtlZeroMemory(targetName, sizeof(targetName)); + + bytesToCopy = *(LoginTargetIn->TargetName); + if (bytesToCopy > (MAX_TARGET_NAME * sizeof(WCHAR))) { + bytesToCopy = MAX_TARGET_NAME * sizeof(WCHAR); + } + + RtlCopyMemory(targetName, + (LoginTargetIn->TargetName + 1), + bytesToCopy); + + rtlStatus = iSpFindPersistentTargetKey( + AdapterExtension, + targetName, + &(LoginTargetIn->TargetPortal), + LoginTargetIn->PortNumber, + &removeTargetKey, + targetKeyName, + sizeof(targetKeyName)/sizeof(targetKeyName[0])); + + if (NT_SUCCESS(rtlStatus) && removeTargetKey != NULL) { + + PWCHAR suffixPtr; + PISCSI_CONNECTION iScsiConnection; + PLIST_ENTRY sessionEntry; + PLIST_ENTRY connectionEntry; + PISCSI_TRANSPORT_ADDRESS targetIPAddress; + ISCSI_TargetPortal targetPortal; + BOOLEAN found = FALSE; + + suffixPtr = wcschr(targetKeyName, L'#'); + if (suffixPtr != NULL) { + + DebugPrint((iScsiPrtDebugInfo, + "Suffix is %ws\n", + suffixPtr)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagProtocolLogInOut, + "Suffix is %ws\n", + suffixPtr); + + RtlZeroMemory(&targetPortal, sizeof(targetPortal)); + + KeAcquireSpinLock(&AdapterExtension->AdapterLock, &oldIrql); + + sessionEntry = AdapterExtension->IScsiSessionList.Flink; + while (sessionEntry != &AdapterExtension->IScsiSessionList) { + + iScsiSession = CONTAINING_RECORD(sessionEntry, + ISCSI_SESSION, + NextSession); + + sessionEntry = sessionEntry->Flink; + + if (wcsncmp(targetName, + iScsiSession->TargetName, + MAX_TARGET_NAME) == 0) { + + connectionEntry = iScsiSession->ConnectionList.Flink; + while (connectionEntry != &iScsiSession->ConnectionList) { + + iScsiConnection = CONTAINING_RECORD(connectionEntry, + ISCSI_CONNECTION, + NextConnection); + + connectionEntry = connectionEntry->Flink; + + targetIPAddress = &(iScsiConnection->TargetIPAddress); + + if (targetIPAddress->AddressType == TDI_ADDRESS_TYPE_IP) { + + targetPortal.Address.Type = ISCSI_IP_ADDRESS_IPV4; + + targetPortal.Socket = + targetIPAddress->IPAddress.IPv4Address.sin_port; + + targetPortal.Address.IpV4Address = + targetIPAddress->IPAddress.IPv4Address.in_addr; + } else { + + targetPortal.Address.Type = ISCSI_IP_ADDRESS_IPV6; + + targetPortal.Socket = + targetIPAddress->IPAddress.IPv6Address.sin6_port; + + targetPortal.Address.IpV6FlowInfo = + targetIPAddress->IPAddress.IPv6Address.sin6_flowinfo; + + targetPortal.Address.IpV6ScopeId = + targetIPAddress->IPAddress.IPv6Address.sin6_scope_id; + + RtlCopyMemory(targetPortal.Address.IpV6Address, + targetIPAddress->IPAddress.IPv6Address.sin6_addr, + sizeof(targetPortal.Address.IpV6Address)); + } + + if (IsSamePortal(&targetPortal, &(LoginTargetIn->TargetPortal))) { + + DebugPrint((iScsiPrtDebugInfo, + "Found session %p\n", + iScsiSession)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagProtocolLogInOut, + "Found session %p\n", + iScsiSession); + + found = TRUE; + break; + } + } + } + + if (found) { + break; + } + } + + KeReleaseSpinLock(&AdapterExtension->AdapterLock, oldIrql); + + if (found) { + + DebugPrint((iScsiPrtDebugInfo, + "Will copy suffix %ws to session %p\n", + suffixPtr, + iScsiSession)); + + ETWDebugPrint(iScsiLevelInfo, + iScsiFlagProtocolLogInOut, + "Will copy suffix %ws to session %p\n", + suffixPtr, + iScsiSession); + + rtlStatus = RtlStringCchCopyNW(iScsiSession->TargetKeyNameSuffix, + TARGET_KEYNAME_SUFFIX_SIZE, + suffixPtr, + (TARGET_KEYNAME_SUFFIX_SIZE - 1)); + + iScsiSession->PersistentLogin = TRUE; + } + } else { + + DebugPrint((iScsiPrtDebugError, + "No suffix found for target %ws\n", + targetKeyName)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "No suffix found for target %ws\n", + targetKeyName); + } + + ZwClose(removeTargetKey); + } else { + + DebugPrint((iScsiPrtDebugError, + "%ws is probably not a persistent target\n", + targetName)); + + ETWDebugPrint(iScsiLevelError, + iScsiFlagProtocolLogInOut, + "%ws is probably not a persistent target\n", + targetName); + + } + + return rtlStatus; +} + |
