Exemplo n.º 1
0
        private T ParseResponse <T>(ProtocolDataUnit pdu)
            where T : BaseResponse, new()
        {
            BaseResponse resp;

            switch (pdu.OpCode)
            {
            case OpCode.LoginResponse:
                resp = new LoginResponse();
                break;

            case OpCode.LogoutResponse:
                resp = new LogoutResponse();
                break;

            case OpCode.ReadyToTransfer:
                resp = new ReadyToTransferPacket();
                break;

            case OpCode.Reject:
                resp = new RejectPacket();
                break;

            case OpCode.ScsiDataIn:
                resp = new DataInPacket();
                break;

            case OpCode.ScsiResponse:
                resp = new Response();
                break;

            case OpCode.TextResponse:
                resp = new TextResponse();
                break;

            default:
                throw new InvalidProtocolException("Unrecognized response opcode: " + pdu.OpCode);
            }

            resp.Parse(pdu);
            if (resp.StatusPresent)
            {
                SeenStatusSequenceNumber(resp.StatusSequenceNumber);
            }

            T result = resp as T;

            if (result == null)
            {
                throw new InvalidProtocolException("Unexpected response, expected " + typeof(T) + ", got " + result.GetType());
            }

            return(result);
        }
Exemplo n.º 2
0
        private ProtocolDataUnit ReadPdu()
        {
            ProtocolDataUnit pdu = ProtocolDataUnit.ReadFrom(_stream, HeaderDigest != Digest.None, DataDigest != Digest.None);

            if (pdu.OpCode == OpCode.Reject)
            {
                RejectPacket pkt = new RejectPacket();
                pkt.Parse(pdu);

                throw new IscsiException("Target sent reject packet, reason " + pkt.Reason);
            }

            return(pdu);
        }
Exemplo n.º 3
0
        public void Close(LogoutReason reason)
        {
            LogoutRequest req = new LogoutRequest(this);

            byte[] packet = req.GetBytes(reason);
            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            ProtocolDataUnit pdu  = ReadPdu();
            LogoutResponse   resp = ParseResponse <LogoutResponse>(pdu);

            if (resp.Response != LogoutResponseCode.ClosedSuccessfully)
            {
                throw new InvalidProtocolException("Target indicated failure during logout: " + resp.Response);
            }

            _stream.Close();
        }
Exemplo n.º 4
0
        private void NegotiateFeatures()
        {
            //
            // Send the request...
            //
            TextBuffer parameters = new TextBuffer();

            GetParametersToNegotiate(parameters, KeyUsagePhase.OperationalNegotiation, _session.SessionType);
            _session.GetParametersToNegotiate(parameters, KeyUsagePhase.OperationalNegotiation);

            byte[] paramBuffer = new byte[parameters.Size];
            parameters.WriteTo(paramBuffer, 0);

            LoginRequest req = new LoginRequest(this);

            byte[] packet = req.GetBytes(paramBuffer, 0, paramBuffer.Length, true);

            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            //
            // Read the response...
            //
            TextBuffer settings = new TextBuffer();

            ProtocolDataUnit pdu  = ReadPdu();
            LoginResponse    resp = ParseResponse <LoginResponse>(pdu);

            if (resp.StatusCode != LoginStatusCode.Success)
            {
                throw new LoginException("iSCSI Target indicated login failure: " + resp.StatusCode);
            }

            if (resp.Continue)
            {
                MemoryStream ms = new MemoryStream();
                ms.Write(resp.TextData, 0, resp.TextData.Length);

                while (resp.Continue)
                {
                    pdu  = ReadPdu();
                    resp = ParseResponse <LoginResponse>(pdu);
                    ms.Write(resp.TextData, 0, resp.TextData.Length);
                }

                settings.ReadFrom(ms.GetBuffer(), 0, (int)ms.Length);
            }
            else if (resp.TextData != null)
            {
                settings.ReadFrom(resp.TextData, 0, resp.TextData.Length);
            }

            parameters = new TextBuffer();
            ConsumeParameters(settings, parameters);

            while (!resp.Transit || parameters.Count != 0)
            {
                paramBuffer = new byte[parameters.Size];
                parameters.WriteTo(paramBuffer, 0);

                req    = new LoginRequest(this);
                packet = req.GetBytes(paramBuffer, 0, paramBuffer.Length, true);

                _stream.Write(packet, 0, packet.Length);
                _stream.Flush();

                //
                // Read the response...
                //
                settings = new TextBuffer();

                pdu  = ReadPdu();
                resp = ParseResponse <LoginResponse>(pdu);

                if (resp.StatusCode != LoginStatusCode.Success)
                {
                    throw new LoginException("iSCSI Target indicated login failure: " + resp.StatusCode);
                }

                parameters = new TextBuffer();

                if (resp.TextData != null)
                {
                    if (resp.Continue)
                    {
                        MemoryStream ms = new MemoryStream();
                        ms.Write(resp.TextData, 0, resp.TextData.Length);

                        while (resp.Continue)
                        {
                            pdu  = ReadPdu();
                            resp = ParseResponse <LoginResponse>(pdu);
                            ms.Write(resp.TextData, 0, resp.TextData.Length);
                        }

                        settings.ReadFrom(ms.GetBuffer(), 0, (int)ms.Length);
                    }
                    else
                    {
                        settings.ReadFrom(resp.TextData, 0, resp.TextData.Length);
                    }

                    ConsumeParameters(settings, parameters);
                }
            }

            if (resp.NextStage != NextLoginStage)
            {
                throw new LoginException("iSCSI Target wants to transition to a different login stage: " + resp.NextStage + " (expected: " + NextLoginStage + ")");
            }

            _loginStage = resp.NextStage;
        }
Exemplo n.º 5
0
        private void NegotiateSecurity()
        {
            _loginStage = LoginStages.SecurityNegotiation;

            //
            // Establish the contents of the request
            //
            TextBuffer parameters = new TextBuffer();

            GetParametersToNegotiate(parameters, KeyUsagePhase.SecurityNegotiation, _session.SessionType);
            _session.GetParametersToNegotiate(parameters, KeyUsagePhase.SecurityNegotiation);

            string authParam = _authenticators[0].Identifier;

            for (int i = 1; i < _authenticators.Length; ++i)
            {
                authParam += "," + _authenticators[i].Identifier;
            }

            parameters.Add(AuthMethodParameter, authParam);

            //
            // Send the request...
            //
            byte[] paramBuffer = new byte[parameters.Size];
            parameters.WriteTo(paramBuffer, 0);

            LoginRequest req = new LoginRequest(this);

            byte[] packet = req.GetBytes(paramBuffer, 0, paramBuffer.Length, true);

            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            //
            // Read the response...
            //
            TextBuffer settings = new TextBuffer();

            ProtocolDataUnit pdu  = ReadPdu();
            LoginResponse    resp = ParseResponse <LoginResponse>(pdu);

            if (resp.StatusCode != LoginStatusCode.Success)
            {
                throw new LoginException("iSCSI Target indicated login failure: " + resp.StatusCode);
            }

            if (resp.Continue)
            {
                MemoryStream ms = new MemoryStream();
                ms.Write(resp.TextData, 0, resp.TextData.Length);

                while (resp.Continue)
                {
                    pdu  = ReadPdu();
                    resp = ParseResponse <LoginResponse>(pdu);
                    ms.Write(resp.TextData, 0, resp.TextData.Length);
                }

                settings.ReadFrom(ms.GetBuffer(), 0, (int)ms.Length);
            }
            else if (resp.TextData != null)
            {
                settings.ReadFrom(resp.TextData, 0, resp.TextData.Length);
            }

            Authenticator authenticator = null;

            for (int i = 0; i < _authenticators.Length; ++i)
            {
                if (settings[AuthMethodParameter] == _authenticators[i].Identifier)
                {
                    authenticator = _authenticators[i];
                    break;
                }
            }

            settings.Remove(AuthMethodParameter);
            settings.Remove("TargetPortalGroupTag");

            if (authenticator == null)
            {
                throw new LoginException("iSCSI Target specified an unsupported authentication method: " + settings[AuthMethodParameter]);
            }

            parameters = new TextBuffer();
            ConsumeParameters(settings, parameters);

            while (!resp.Transit)
            {
                //
                // Send the request...
                //
                parameters = new TextBuffer();
                authenticator.GetParameters(parameters);
                paramBuffer = new byte[parameters.Size];
                parameters.WriteTo(paramBuffer, 0);

                req    = new LoginRequest(this);
                packet = req.GetBytes(paramBuffer, 0, paramBuffer.Length, true);

                _stream.Write(packet, 0, packet.Length);
                _stream.Flush();

                //
                // Read the response...
                //
                settings = new TextBuffer();

                pdu  = ReadPdu();
                resp = ParseResponse <LoginResponse>(pdu);

                if (resp.StatusCode != LoginStatusCode.Success)
                {
                    throw new LoginException("iSCSI Target indicated login failure: " + resp.StatusCode);
                }

                if (resp.TextData != null && resp.TextData.Length != 0)
                {
                    if (resp.Continue)
                    {
                        MemoryStream ms = new MemoryStream();
                        ms.Write(resp.TextData, 0, resp.TextData.Length);

                        while (resp.Continue)
                        {
                            pdu  = ReadPdu();
                            resp = ParseResponse <LoginResponse>(pdu);
                            ms.Write(resp.TextData, 0, resp.TextData.Length);
                        }

                        settings.ReadFrom(ms.GetBuffer(), 0, (int)ms.Length);
                    }
                    else
                    {
                        settings.ReadFrom(resp.TextData, 0, resp.TextData.Length);
                    }

                    authenticator.SetParameters(settings);
                }
            }

            if (resp.NextStage != NextLoginStage)
            {
                throw new LoginException("iSCSI Target wants to transition to a different login stage: " + resp.NextStage + " (expected: " + NextLoginStage + ")");
            }

            _loginStage = resp.NextStage;
        }
Exemplo n.º 6
0
        public TargetInfo[] EnumerateTargets()
        {
            TextBuffer parameters = new TextBuffer();

            parameters.Add(SendTargetsParameter, "All");

            byte[] paramBuffer = new byte[parameters.Size];
            parameters.WriteTo(paramBuffer, 0);

            TextRequest req = new TextRequest(this);

            byte[] packet = req.GetBytes(0, paramBuffer, 0, paramBuffer.Length, true);

            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            ProtocolDataUnit pdu  = ReadPdu();
            TextResponse     resp = ParseResponse <TextResponse>(pdu);

            TextBuffer buffer = new TextBuffer();

            if (resp.TextData != null)
            {
                buffer.ReadFrom(resp.TextData, 0, resp.TextData.Length);
            }

            List <TargetInfo> targets = new List <TargetInfo>();

            string currentTarget = null;
            List <TargetAddress> currentAddresses = null;

            foreach (var line in buffer.Lines)
            {
                if (currentTarget == null)
                {
                    if (line.Key != TargetNameParameter)
                    {
                        throw new InvalidProtocolException("Unexpected response parameter " + line.Key + " expected " + TargetNameParameter);
                    }

                    currentTarget    = line.Value;
                    currentAddresses = new List <TargetAddress>();
                }
                else if (line.Key == TargetNameParameter)
                {
                    targets.Add(new TargetInfo(currentTarget, currentAddresses.ToArray()));
                    currentTarget = line.Value;
                    currentAddresses.Clear();
                }
                else if (line.Key == TargetAddressParameter)
                {
                    currentAddresses.Add(TargetAddress.Parse(line.Value));
                }
            }

            if (currentTarget != null)
            {
                targets.Add(new TargetInfo(currentTarget, currentAddresses.ToArray()));
            }

            return(targets.ToArray());
        }
Exemplo n.º 7
0
        /// <summary>
        /// Sends an SCSI command (aka task) to a LUN via the connected target.
        /// </summary>
        /// <param name="cmd">The command to send</param>
        /// <param name="outBuffer">The data to send with the command</param>
        /// <param name="outBufferOffset">The offset of the first byte to send</param>
        /// <param name="outBufferCount">The number of bytes to send, if any</param>
        /// <param name="inBuffer">The buffer to fill with returned data</param>
        /// <param name="inBufferOffset">The first byte to fill with returned data</param>
        /// <param name="inBufferMax">The maximum amount of data to receive</param>
        /// <returns>The number of bytes received</returns>
        public int Send(ScsiCommand cmd, byte[] outBuffer, int outBufferOffset, int outBufferCount, byte[] inBuffer, int inBufferOffset, int inBufferMax)
        {
            CommandRequest req = new CommandRequest(this, cmd.TargetLun);

            int toSend = Math.Min(Math.Min(outBufferCount, _session.ImmediateData ? _session.FirstBurstLength : 0), MaxTargetReceiveDataSegmentLength);

            byte[] packet = req.GetBytes(cmd, outBuffer, outBufferOffset, toSend, true, inBufferMax != 0, outBufferCount != 0, (uint)(outBufferCount != 0 ? outBufferCount : inBufferMax));
            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            int numApproved = 0;
            int numSent     = toSend;
            int pktsSent    = 0;

            while (numSent < outBufferCount)
            {
                ProtocolDataUnit pdu = ReadPdu();

                ReadyToTransferPacket resp = ParseResponse <ReadyToTransferPacket>(pdu);
                numApproved = (int)resp.DesiredTransferLength;
                uint targetTransferTag = resp.TargetTransferTag;

                while (numApproved > 0)
                {
                    toSend = Math.Min(Math.Min(outBufferCount - numSent, numApproved), MaxTargetReceiveDataSegmentLength);

                    DataOutPacket pkt = new DataOutPacket(this, cmd.TargetLun);
                    packet = pkt.GetBytes(outBuffer, outBufferOffset + numSent, toSend, toSend == numApproved, pktsSent++, (uint)numSent, targetTransferTag);
                    _stream.Write(packet, 0, packet.Length);
                    _stream.Flush();

                    numApproved -= toSend;
                    numSent     += toSend;
                }
            }

            bool isFinal = false;
            int  numRead = 0;

            while (!isFinal)
            {
                ProtocolDataUnit pdu = ReadPdu();

                if (pdu.OpCode == OpCode.ScsiResponse)
                {
                    Response resp = ParseResponse <Response>(pdu);

                    if (resp.StatusPresent && resp.Status == ScsiStatus.CheckCondition)
                    {
                        ushort senseLength = Utilities.ToUInt16BigEndian(pdu.ContentData, 0);
                        byte[] senseData   = new byte[senseLength];
                        Array.Copy(pdu.ContentData, 2, senseData, 0, senseLength);
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure", senseData);
                    }
                    else if (resp.StatusPresent && resp.Status != ScsiStatus.Good)
                    {
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure");
                    }

                    isFinal = resp.Header.FinalPdu;
                }
                else if (pdu.OpCode == OpCode.ScsiDataIn)
                {
                    DataInPacket resp = ParseResponse <DataInPacket>(pdu);

                    if (resp.StatusPresent && resp.Status != ScsiStatus.Good)
                    {
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure");
                    }

                    if (resp.ReadData != null)
                    {
                        Array.Copy(resp.ReadData, 0, inBuffer, inBufferOffset + resp.BufferOffset, resp.ReadData.Length);
                        numRead += resp.ReadData.Length;
                    }

                    isFinal = resp.Header.FinalPdu;
                }
            }

            _session.NextTaskTag();
            _session.NextCommandSequenceNumber();

            return(numRead);
        }