123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /* Copyright (C) 2012-2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
- *
- * You can redistribute this program and/or modify it under the terms of
- * the GNU Lesser Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- */
- using System;
- using System.Collections.Generic;
- using System.Net;
- using System.Text;
- using Utilities;
- namespace ISCSI.Server
- {
- public class ServerResponseHelper
- {
- // CmdSN is session wide
- // StatSN is per connection
-
- internal static NOPInPDU GetNOPResponsePDU(NOPOutPDU request)
- {
- NOPInPDU response = new NOPInPDU();
- response.Data = request.Data;
- // When a target receives the NOP-Out with a valid Initiator Task Tag (not the reserved value 0xffffffff),
- // it MUST respond with a NOP-In with the same Initiator Task Tag that was provided in the NOP-Out request.
- // For such a response, the Target Transfer Tag MUST be 0xffffffff
- response.InitiatorTaskTag = request.InitiatorTaskTag;
- response.TargetTransferTag = 0xFFFFFFFF;
- return response;
- }
- internal static LoginResponsePDU GetLoginResponsePDU(LoginRequestPDU request, List<ISCSITarget> availableTargets, SessionParameters session, ConnectionParameters connection, ref ISCSITarget target, GetNextTSIH GetNextTSIH)
- {
- LoginResponsePDU response = new LoginResponsePDU();
- response.Transit = request.Transit;
- response.Continue = false;
-
- // The stage codes are:
- // 0 - SecurityNegotiation
- // 1 - LoginOperationalNegotiation
- // 3 - FullFeaturePhase
- response.CurrentStage = request.CurrentStage;
- response.NextStage = request.NextStage;
- response.VersionMax = request.VersionMax;
- response.VersionActive = request.VersionMin;
- response.ISID = request.ISID;
- response.Status = LoginResponseStatusName.Success;
- response.InitiatorTaskTag = request.InitiatorTaskTag;
- if (request.TSIH == 0)
- {
- // For a new session, the request TSIH is zero,
- // As part of the response, the target generates a TSIH.
- session.TSIH = GetNextTSIH();
- }
- response.TSIH = session.TSIH;
- if (request.Transit && request.Continue)
- {
- response.Status = LoginResponseStatusName.InitiatorError;
- return response;
- }
- else if (request.Continue)
- {
- response.Status = LoginResponseStatusName.Success;
- return response;
- }
- // RFC 3720: The login process proceeds in two stages - the security negotiation
- // stage and the operational parameter negotiation stage. Both stages are optional
- // but at least one of them has to be present.
- bool firstLoginRequest = (!session.IsDiscovery && target == null);
- if (firstLoginRequest)
- {
- string sessionType = request.LoginParameters.ValueOf("SessionType");
- if (sessionType == "Discovery")
- {
- session.IsDiscovery = true;
- }
- else //sessionType == "Normal" or unspecified (default is Normal)
- {
- session.IsDiscovery = false;
- // 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.
- if (request.LoginParameters.ContainsKey("TargetName"))
- {
- string targetName = request.LoginParameters.ValueOf("TargetName");
- int targetIndex = GetTargetIndex(availableTargets, targetName);
- if (targetIndex >= 0)
- {
- target = availableTargets[targetIndex];
- }
- else
- {
- response.Status = LoginResponseStatusName.NotFound;
- return response;
- }
- }
- else
- {
- response.Status = LoginResponseStatusName.InitiatorError;
- return response;
- }
- }
- }
- if (request.CurrentStage == 0)
- {
- response.LoginParameters.Add("AuthMethod", "None");
-
- if (request.Transit && request.NextStage != 1 && request.NextStage != 3)
- {
- response.Status = LoginResponseStatusName.InitiatorError;
- }
- }
- else if (request.CurrentStage == 1)
- {
- UpdateOperationalParameters(request.LoginParameters, session, connection);
- response.LoginParameters = GetLoginOperationalParameters(session, connection);
- if (request.Transit && request.NextStage != 3)
- {
- response.Status = LoginResponseStatusName.InitiatorError;
- }
- }
- else
- {
- // Not valid
- response.Status = LoginResponseStatusName.InitiatorError;
- }
- return response;
- }
- private static int GetTargetIndex(List<ISCSITarget> targets, string targetName)
- {
- for (int index = 0; index < targets.Count; index++)
- {
- if (String.Equals(targets[index].TargetName, targetName, StringComparison.InvariantCultureIgnoreCase))
- {
- return index;
- }
- }
- return -1;
- }
- public static void UpdateOperationalParameters(KeyValuePairList<string, string> loginParameters, SessionParameters sessionParameters, ConnectionParameters connectionParameters)
- {
- sessionParameters.InitialR2T = ISCSIServer.OfferedInitialR2T;
- sessionParameters.ImmediateData = ISCSIServer.OfferedImmediateData;
- sessionParameters.MaxBurstLength = ISCSIServer.OfferedMaxBurstLength;
- sessionParameters.FirstBurstLength = ISCSIServer.OfferedFirstBurstLength;
- sessionParameters.MaxConnections = ISCSIServer.OfferedMaxConnections;
- sessionParameters.DataPDUInOrder = ISCSIServer.OfferedDataPDUInOrder;
- sessionParameters.DataSequenceInOrder = ISCSIServer.OfferedDataSequenceInOrder;
- sessionParameters.DefaultTime2Wait = ISCSIServer.OfferedDefaultTime2Wait;
- sessionParameters.DefaultTime2Retain = ISCSIServer.OfferedDefaultTime2Retain;
- sessionParameters.MaxOutstandingR2T = ISCSIServer.OfferedMaxOutstandingR2T;
- string value = loginParameters.ValueOf("MaxRecvDataSegmentLength");
- if (value != null)
- {
- connectionParameters.InitiatorMaxRecvDataSegmentLength = Convert.ToInt32(value);
- }
- value = loginParameters.ValueOf("InitialR2T");
- if (value != null)
- {
- sessionParameters.InitialR2T = (value == "Yes") || ISCSIServer.OfferedInitialR2T;
- }
- value = loginParameters.ValueOf("ImmediateData");
- if (value != null)
- {
- sessionParameters.ImmediateData = (value == "Yes") && ISCSIServer.OfferedImmediateData;
- }
- value = loginParameters.ValueOf("MaxBurstLength");
- if (value != null)
- {
- sessionParameters.MaxBurstLength = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxBurstLength);
- }
- value = loginParameters.ValueOf("FirstBurstLength");
- if (value != null)
- {
- sessionParameters.FirstBurstLength = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedFirstBurstLength);
- }
- value = loginParameters.ValueOf("MaxConnections");
- if (value != null)
- {
- sessionParameters.MaxConnections = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxConnections);
- }
- value = loginParameters.ValueOf("DataPDUInOrder");
- if (value != null)
- {
- sessionParameters.DataPDUInOrder = (value == "Yes") || ISCSIServer.OfferedDataPDUInOrder;
- }
- value = loginParameters.ValueOf("DataSequenceInOrder");
- if (value != null)
- {
- sessionParameters.DataSequenceInOrder = (value == "Yes") || ISCSIServer.OfferedDataSequenceInOrder;
- }
- value = loginParameters.ValueOf("DefaultTime2Wait");
- if (value != null)
- {
- sessionParameters.DefaultTime2Wait = Math.Max(Convert.ToInt32(value), ISCSIServer.OfferedDefaultTime2Wait);
- }
- value = loginParameters.ValueOf("DefaultTime2Retain");
- if (value != null)
- {
- sessionParameters.DefaultTime2Retain = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedDefaultTime2Retain);
- }
- value = loginParameters.ValueOf("MaxOutstandingR2T");
- if (value != null)
- {
- sessionParameters.MaxOutstandingR2T = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxOutstandingR2T);
- }
- }
- public static KeyValuePairList<string, string> GetLoginOperationalParameters(SessionParameters sessionParameters, ConnectionParameters connectionParameters)
- {
- KeyValuePairList<string, string> loginParameters = new KeyValuePairList<string, string>();
- loginParameters.Add("HeaderDigest", "None");
- loginParameters.Add("DataDigest", "None");
- loginParameters.Add("MaxRecvDataSegmentLength", connectionParameters.TargetMaxRecvDataSegmentLength.ToString());
- if (!sessionParameters.IsDiscovery)
- {
- loginParameters.Add("ErrorRecoveryLevel", ISCSIServer.OfferedErrorRecoveryLevel.ToString());
- loginParameters.Add("InitialR2T", sessionParameters.InitialR2T ? "Yes" : "No"); // Microsoft iSCSI Target support InitialR2T = No
- loginParameters.Add("ImmediateData", sessionParameters.ImmediateData ? "Yes" : "No");
- loginParameters.Add("MaxBurstLength", sessionParameters.MaxBurstLength.ToString());
- loginParameters.Add("FirstBurstLength", sessionParameters.FirstBurstLength.ToString());
- loginParameters.Add("MaxConnections", sessionParameters.MaxConnections.ToString());
- loginParameters.Add("DataPDUInOrder", sessionParameters.DataPDUInOrder ? "Yes" : "No");
- loginParameters.Add("DataSequenceInOrder", sessionParameters.DataSequenceInOrder ? "Yes" : "No");
- loginParameters.Add("MaxOutstandingR2T", sessionParameters.MaxOutstandingR2T.ToString());
- }
- loginParameters.Add("DefaultTime2Wait", sessionParameters.DefaultTime2Wait.ToString());
- loginParameters.Add("DefaultTime2Retain", sessionParameters.DefaultTime2Retain.ToString());
-
- return loginParameters;
- }
- internal static TextResponsePDU GetTextResponsePDU(TextRequestPDU request, List<ISCSITarget> targets)
- {
- TextResponsePDU response = new TextResponsePDU();
- response.Final = true;
- response.InitiatorTaskTag = request.InitiatorTaskTag;
- KeyValuePairList<string, string> entries = new KeyValuePairList<string, string>();
- foreach (ISCSITarget target in targets)
- {
- entries.Add("TargetName", target.TargetName);
- }
- response.Text = KeyValuePairUtils.ToNullDelimitedString(entries);
- return response;
- }
- internal static LogoutResponsePDU GetLogoutResponsePDU(LogoutRequestPDU request)
- {
- LogoutResponsePDU response = new LogoutResponsePDU();
- response.Response = LogoutResponse.ClosedSuccessfully;
- response.Final = true;
- response.InitiatorTaskTag = request.InitiatorTaskTag;
- return response;
- }
- }
- }
|