Exemple #1
0
        internal static NOPOutPDU GetPingRequest(SessionParameters session, ConnectionParameters connection)
        {
            // Microsoft iSCSI Target v3.1 expects that CmdSN won't be incremented after this request regardless of whether the ImmediateDelivery bit is set or not,
            // So we set the ImmediateDelivery bit to work around the issue.
            NOPOutPDU request = new NOPOutPDU();

            request.ImmediateDelivery = true;
            request.InitiatorTaskTag  = session.GetNextTaskTag();
            request.CmdSN             = session.GetNextCmdSN(false);
            // RFC 3720: The NOP-Out MUST only have the Target Transfer Tag set if it is issued in response to a NOP-In (with a valid Target Transfer Tag).
            // Otherwise, the Target Transfer Tag MUST be set to 0xffffffff.
            request.TargetTransferTag = 0xFFFFFFFF;
            return(request);
        }
Exemple #2
0
        internal static NOPOutPDU GetPingResponse(NOPInPDU request, SessionParameters session, ConnectionParameters connection)
        {
            NOPOutPDU response = new NOPOutPDU();

            // If the Initiator Task Tag contains 0xffffffff, the I bit MUST be set to 1 and the CmdSN is not advanced after this PDU is sent.
            response.ImmediateDelivery = true;
            // RFC 3720: The NOP-Out MUST have the Initiator Task Tag set to a valid value only if a response in the form of NOP-In is requested.
            // Otherwise, the Initiator Task Tag MUST be set to 0xffffffff
            response.InitiatorTaskTag  = 0xFFFFFFFF;
            response.CmdSN             = session.GetNextCmdSN(false);
            response.TargetTransferTag = request.TargetTransferTag;
            // p.s. the Data Segment (of the request sent by the target) MUST NOT contain any data
            return(response);
        }
Exemple #3
0
        internal static SCSICommandPDU GetReportLUNsCommand(SessionParameters session, ConnectionParameters connection, uint allocationLength)
        {
            SCSICommandDescriptorBlock reportLUNs = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReportLUNs);

            reportLUNs.TransferLength = allocationLength;

            SCSICommandPDU scsiCommand = new SCSICommandPDU();

            scsiCommand.CommandDescriptorBlock = reportLUNs.GetBytes();
            scsiCommand.InitiatorTaskTag       = session.GetNextTaskTag();
            scsiCommand.Final = true;
            scsiCommand.Read  = true;
            scsiCommand.CmdSN = session.GetNextCmdSN(true);
            scsiCommand.ExpectedDataTransferLength = allocationLength;
            return(scsiCommand);
        }
Exemple #4
0
        internal static SCSICommandPDU GetReadCapacity10Command(SessionParameters session, ConnectionParameters connection, ushort LUN)
        {
            SCSICommandDescriptorBlock readCapacity10 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReadCapacity10);

            readCapacity10.TransferLength = ReadCapacity10Parameter.Length;

            SCSICommandPDU scsiCommand = new SCSICommandPDU();

            scsiCommand.CommandDescriptorBlock = readCapacity10.GetBytes();
            scsiCommand.InitiatorTaskTag       = session.GetNextTaskTag();
            scsiCommand.Final = true;
            scsiCommand.Read  = true;
            scsiCommand.LUN   = LUN;
            scsiCommand.CmdSN = session.GetNextCmdSN(true);
            scsiCommand.ExpectedDataTransferLength = ReadCapacity10Parameter.Length;
            return(scsiCommand);
        }
Exemple #5
0
        internal static SCSICommandPDU GetRead16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, uint sectorCount, int bytesPerSector)
        {
            SCSICommandDescriptorBlock read16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Read16);

            read16.LogicalBlockAddress64 = sectorIndex;
            read16.TransferLength        = sectorCount;

            SCSICommandPDU scsiCommand = new SCSICommandPDU();

            scsiCommand.CommandDescriptorBlock = read16.GetBytes();
            scsiCommand.LUN = LUN;
            scsiCommand.InitiatorTaskTag           = session.GetNextTaskTag();
            scsiCommand.Final                      = true;
            scsiCommand.Read                       = true;
            scsiCommand.CmdSN                      = session.GetNextCmdSN(true);
            scsiCommand.ExpectedDataTransferLength = (uint)(sectorCount * bytesPerSector);
            return(scsiCommand);
        }
Exemple #6
0
        internal static SCSICommandPDU GetWrite16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, byte[] data, int bytesPerSector)
        {
            SCSICommandDescriptorBlock write16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Write16);

            write16.LogicalBlockAddress64 = sectorIndex;
            write16.TransferLength        = (uint)(data.Length / bytesPerSector);

            SCSICommandPDU scsiCommand = new SCSICommandPDU();

            scsiCommand.CommandDescriptorBlock = write16.GetBytes();
            if (session.ImmediateData)
            {
                int immediateDataLength = Math.Min(data.Length, session.FirstBurstLength);
                scsiCommand.Data = ByteReader.ReadBytes(data, 0, immediateDataLength);
            }
            scsiCommand.LUN = LUN;
            scsiCommand.InitiatorTaskTag           = session.GetNextTaskTag();
            scsiCommand.Final                      = true;
            scsiCommand.Write                      = true;
            scsiCommand.CmdSN                      = session.GetNextCmdSN(true);
            scsiCommand.ExpectedDataTransferLength = (uint)(data.Length);
            return(scsiCommand);
        }
Exemple #7
0
        internal static List <SCSIDataOutPDU> GetWriteData(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, byte[] data, int bytesPerSector, ReadyToTransferPDU readyToTransfer)
        {
            List <SCSIDataOutPDU> result = new List <SCSIDataOutPDU>();
            // if readyToTransfer.DesiredDataTransferLength <= connection.TargetMaxRecvDataSegmentLength we must send multiple Data-Out PDUs
            // We assume DesiredDataTransferLength does not violate session.MaxBurstLength
            int numberOfChunks = (int)Math.Ceiling((double)readyToTransfer.DesiredDataTransferLength / connection.TargetMaxRecvDataSegmentLength);

            for (int chunkIndex = 0; chunkIndex < numberOfChunks; chunkIndex++)
            {
                int            chunkOffset = chunkIndex * connection.TargetMaxRecvDataSegmentLength;
                int            chunkLength = (int)Math.Min(connection.TargetMaxRecvDataSegmentLength, readyToTransfer.DesiredDataTransferLength - chunkOffset);
                SCSIDataOutPDU dataOut     = new SCSIDataOutPDU();
                dataOut.BufferOffset      = readyToTransfer.BufferOffset + (uint)chunkOffset;
                dataOut.Data              = ByteReader.ReadBytes(data, (int)dataOut.BufferOffset, chunkLength);
                dataOut.TargetTransferTag = readyToTransfer.TargetTransferTag;
                dataOut.InitiatorTaskTag  = readyToTransfer.InitiatorTaskTag;
                if (chunkIndex == numberOfChunks - 1)
                {
                    dataOut.Final = true;
                }
                result.Add(dataOut);
            }
            return(result);
        }
Exemple #8
0
        internal static LoginRequestPDU GetSingleStageLoginRequest(string initiatorName, string targetName, SessionParameters session, ConnectionParameters connection)
        {
            LoginRequestPDU request = new LoginRequestPDU();

            request.ISID             = session.ISID;
            request.TSIH             = session.TSIH;
            request.CID              = connection.CID;
            request.InitiatorTaskTag = session.GetNextTaskTag();
            request.CmdSN            = session.GetNextCmdSN(false);
            request.CurrentStage     = 1;
            request.NextStage        = 3;
            request.Transit          = true;
            request.VersionMax       = 0;
            request.VersionMin       = 0;
            request.LoginParameters.Add("InitiatorName", initiatorName);
            if (targetName == null)
            {
                request.LoginParameters.Add("SessionType", "Discovery");
            }
            else
            {
                request.LoginParameters.Add("SessionType", "Normal");
                request.LoginParameters.Add("TargetName", targetName);
            }
            request.LoginParameters.Add("DataDigest", "None");
            request.LoginParameters.Add("MaxRecvDataSegmentLength", connection.InitiatorMaxRecvDataSegmentLength.ToString());
            if (targetName != null)
            {
                request.LoginParameters.Add("ErrorRecoveryLevel", ISCSIClient.OfferedErrorRecoveryLevel.ToString());
                request.LoginParameters.Add("InitialR2T", ISCSIClient.OfferedInitialR2T ? "Yes" : "No");
                request.LoginParameters.Add("ImmediateData", ISCSIClient.OfferedImmediateData ? "Yes" : "No");
                request.LoginParameters.Add("MaxBurstLength", ISCSIClient.OfferedMaxBurstLength.ToString());
                request.LoginParameters.Add("FirstBurstLength", ISCSIClient.OfferedFirstBurstLength.ToString());
                request.LoginParameters.Add("MaxConnections", ISCSIClient.OfferedMaxConnections.ToString());
                request.LoginParameters.Add("DataPDUInOrder", ISCSIClient.OfferedDataPDUInOrder ? "Yes" : "No");
                request.LoginParameters.Add("DataSequenceInOrder", ISCSIClient.OfferedDataSequenceInOrder ? "Yes" : "No");
                request.LoginParameters.Add("MaxOutstandingR2T", ISCSIClient.OfferedMaxOutstandingR2T.ToString());
            }
            request.LoginParameters.Add("DefaultTime2Wait", ISCSIClient.OfferedDefaultTime2Wait.ToString());
            request.LoginParameters.Add("DefaultTime2Retain", ISCSIClient.OfferedDefaultTime2Retain.ToString());

            return(request);
        }
Exemple #9
0
        internal static LoginRequestPDU GetSecondStageLoginRequest(LoginResponsePDU firstStageResponse, SessionParameters session, ConnectionParameters connection, bool isDiscovery)
        {
            LoginRequestPDU request = new LoginRequestPDU();

            request.ISID             = firstStageResponse.ISID;
            request.TSIH             = firstStageResponse.TSIH;
            request.CID              = connection.CID;
            request.InitiatorTaskTag = session.GetNextTaskTag();
            request.CmdSN            = session.GetNextCmdSN(false);
            request.CurrentStage     = firstStageResponse.NextStage;
            request.NextStage        = 3;
            request.Transit          = true;
            request.VersionMax       = 0;
            request.VersionMin       = 0;
            request.LoginParameters.Add("HeaderDigest", "None");
            request.LoginParameters.Add("DataDigest", "None");
            request.LoginParameters.Add("MaxRecvDataSegmentLength", connection.InitiatorMaxRecvDataSegmentLength.ToString());
            if (!isDiscovery)
            {
                request.LoginParameters.Add("ErrorRecoveryLevel", ISCSIClient.OfferedErrorRecoveryLevel.ToString());
                request.LoginParameters.Add("InitialR2T", ISCSIClient.OfferedInitialR2T ? "Yes" : "No");
                request.LoginParameters.Add("ImmediateData", ISCSIClient.OfferedImmediateData ? "Yes" : "No");
                request.LoginParameters.Add("MaxBurstLength", ISCSIClient.OfferedMaxBurstLength.ToString());
                request.LoginParameters.Add("FirstBurstLength", ISCSIClient.OfferedFirstBurstLength.ToString());
                request.LoginParameters.Add("MaxConnections", ISCSIClient.OfferedMaxConnections.ToString());
                request.LoginParameters.Add("DataPDUInOrder", ISCSIClient.OfferedDataPDUInOrder ? "Yes" : "No");
                request.LoginParameters.Add("DataSequenceInOrder", ISCSIClient.OfferedDataSequenceInOrder ? "Yes" : "No");
                request.LoginParameters.Add("MaxOutstandingR2T", ISCSIClient.OfferedMaxOutstandingR2T.ToString());
            }
            request.LoginParameters.Add("DefaultTime2Wait", ISCSIClient.OfferedDefaultTime2Wait.ToString());
            request.LoginParameters.Add("DefaultTime2Retain", ISCSIClient.OfferedDefaultTime2Retain.ToString());

            return(request);
        }
Exemple #10
0
        /// <param name="targetName">Set to null for discovery session</param>
        internal static LoginRequestPDU GetFirstStageLoginRequest(string initiatorName, string targetName, SessionParameters session, ConnectionParameters connection)
        {
            LoginRequestPDU request = new LoginRequestPDU();

            request.InitiatorTaskTag = session.GetNextTaskTag();
            request.ISID             = session.ISID;
            request.TSIH             = 0; // used on the first connection for a new session
            request.CID       = connection.CID;
            request.CmdSN     = session.GetNextCmdSN(false);
            request.ExpStatSN = 0;
            // The stage codes are:
            // 0 - SecurityNegotiation
            // 1 - LoginOperationalNegotiation
            // 3 - FullFeaturePhase
            request.CurrentStage = 0;
            request.NextStage    = 1;
            request.Transit      = true;
            request.VersionMax   = 0;
            request.VersionMin   = 0;
            request.LoginParameters.Add("InitiatorName", initiatorName);
            request.LoginParameters.Add("AuthMethod", "None");
            if (targetName == null)
            {
                request.LoginParameters.Add("SessionType", "Discovery");
            }
            else
            {
                // RFC 3720: For any connection within a session whose type is not "Discovery", the first Login Request MUST also include the TargetName key=value pair.
                request.LoginParameters.Add("SessionType", "Normal");
                request.LoginParameters.Add("TargetName", targetName);
            }
            return(request);
        }
Exemple #11
0
        internal static void UpdateOperationalParameters(KeyValuePairList <string, string> loginParameters, SessionParameters session, ConnectionParameters connection)
        {
            session.InitialR2T          = ISCSIClient.OfferedInitialR2T;
            session.ImmediateData       = ISCSIClient.OfferedImmediateData;
            session.MaxBurstLength      = ISCSIClient.OfferedMaxBurstLength;
            session.FirstBurstLength    = ISCSIClient.OfferedFirstBurstLength;
            session.DefaultTime2Wait    = ISCSIClient.OfferedDefaultTime2Wait;
            session.DefaultTime2Retain  = ISCSIClient.OfferedDefaultTime2Retain;
            session.MaxOutstandingR2T   = ISCSIClient.OfferedMaxOutstandingR2T;
            session.DataPDUInOrder      = ISCSIClient.OfferedDataPDUInOrder;
            session.DataSequenceInOrder = ISCSIClient.OfferedDataSequenceInOrder;
            session.ErrorRecoveryLevel  = ISCSIClient.OfferedErrorRecoveryLevel;

            string value = loginParameters.ValueOf("MaxRecvDataSegmentLength");

            if (value != null)
            {
                connection.TargetMaxRecvDataSegmentLength = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("InitialR2T");
            if (value != null)
            {
                session.InitialR2T = (value == "Yes") ? true : false;
            }

            value = loginParameters.ValueOf("ImmediateData");
            if (value != null)
            {
                session.ImmediateData = (value == "Yes") ? true : false;
            }

            value = loginParameters.ValueOf("MaxBurstLength");
            if (value != null)
            {
                session.MaxBurstLength = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("FirstBurstLength");
            if (value != null)
            {
                session.FirstBurstLength = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("DefaultTime2Wait");
            if (value != null)
            {
                session.DefaultTime2Wait = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("DefaultTime2Retain");
            if (value != null)
            {
                session.DefaultTime2Retain = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("MaxOutstandingR2T");
            if (value != null)
            {
                session.MaxOutstandingR2T = Convert.ToInt32(value);
            }

            value = loginParameters.ValueOf("DataPDUInOrder");
            if (value != null)
            {
                session.DataPDUInOrder = (value == "Yes") ? true : false;
            }

            value = loginParameters.ValueOf("DataSequenceInOrder");
            if (value != null)
            {
                session.DataSequenceInOrder = (value == "Yes") ? true : false;
            }

            value = loginParameters.ValueOf("ErrorRecoveryLevel");
            if (value != null)
            {
                session.ErrorRecoveryLevel = Convert.ToInt32(value);
            }
        }