summaryrefslogtreecommitdiff
path: root/storage/iscsi/src/client
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/iscsi/src/client
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'storage/iscsi/src/client')
-rw-r--r--storage/iscsi/src/client/wmisample.c7990
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,
+ &regValue, &regValueSize);
+ 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;
+}
+