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;
        }
        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...
                //
                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;
        }