public static void Disconnect()
        {
            Condition.IsTrue(Open != null);

            if (Open.IsPersistent   // TDI, server will preserve the open for reconnect if Open.IsPersistent is true.
                || (Open.IsDurable
                    && (Open.IsBatchOplockExisted
                    || Open.IsLeaseExisted)))
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.7.1: The server MUST iterate over the Session.OpenTable and determine whether each Open is to be preserved for reconnect. " +
                    "If any of the following conditions is satisfied, it indicates that the Open is to be preserved for reconnect. ");

                if (Open.IsBatchOplockExisted)
                {
                    ModelHelper.Log(LogType.Requirement, "\tOpen.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH and Open.OplockState is equal to Held, and Open.IsDurable is TRUE.");
                    ModelHelper.Log(LogType.TestInfo, "The above condition is met.");
                }

                if (Open.IsLeaseExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "\tOpen.OplockLevel is equal to SMB2_OPLOCK_LEVEL_LEASE, Lease.LeaseState contains SMB2_LEASE_HANDLE_CACHING, " +
                        "Open.OplockState is equal to Held, and Open.IsDurable is TRUE.");
                    ModelHelper.Log(LogType.TestInfo, "The above condition is met.");
                }

                ModelHelper.Log(LogType.TestInfo, "The Open is to be preserved.");

                ModelHelper.Log(LogType.Requirement,
                    "If the Open is to be preserved for reconnect, perform the following actions: ");
                ModelHelper.Log(LogType.Requirement,
                    "\tSet Open.Connection to NULL, Open.Session to NULL, Open.TreeConnect to NULL. ");
                ModelHelper.Log(LogType.TestInfo, "Open.Connection and Open.Session are set to NULL.");

                Open.IsConnectionExisted = false;
                Open.IsSessionExisted = false;
            }
            else
            {
                ModelHelper.Log(LogType.Requirement, "3.3.7.1: If the Open is not to be preserved for reconnect, the server MUST close the Open as specified in section 3.3.4.17.");
                ModelHelper.Log(LogType.TestInfo, "The Open is closed.");
                Open = null;
            }
        }
        public static void LogOff()
        {
            Condition.IsTrue(Open != null);

            if (!Open.IsDurable)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.6: The server MUST close every Open in Session.OpenTable of the old session, " +
                    "where Open.IsDurable is FALSE and Open.IsResilient is FALSE, as specified in section 3.3.4.17. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is FALSE and Open.IsResilient is FALSE, so the open is closed.");
                Open = null;
            }
            else
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.6: For all opens in Session.OpenTable where Open.IsDurable is TRUE or Open.IsResilient is TRUE, " +
                    "the server MUST set Open.Session, Open.Connection, and Open.TreeConnect to NULL. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is TRUE, so Open.Session, Open.Connection is set to NULL.");
                Open.IsSessionExisted = false;
                Open.IsConnectionExisted = false;
            }
        }
        public static void PrepareOpen(
            ModelDialectRevision clientMaxDialect,
            PersistentBitType persistentBit,
            CAShareType connectToCAShare,
            ModelHandleType modelHandleType,
            OplockLeaseType oplockLeaseType)
        {
            Condition.IsNull(Request);
            Condition.IsNull(Open);

            // CAShare, Persistent Handle , Durable Handle v2 and Lease V2 are only applied for SMB 3.x family.
            Condition.IfThen(!ModelUtility.IsSmb3xFamily(Config.MaxSmbVersionSupported), connectToCAShare == CAShareType.NonCAShare);
            Condition.IfThen(!ModelUtility.IsSmb3xFamily(Config.MaxSmbVersionSupported), persistentBit == PersistentBitType.PersistentBitNotSet);
            Condition.IfThen(!ModelUtility.IsSmb3xFamily(Config.MaxSmbVersionSupported), modelHandleType == ModelHandleType.DurableHandleV1);

            // Case will go to non-accpeting state if clientMaxDialect > Config.MaxSmbVersionSupported.
            NegotiateDialect = ModelHelper.DetermineNegotiateDialect(clientMaxDialect, Config.MaxSmbVersionSupported);

            // Restrict the params combination
            Combination.Pairwise(clientMaxDialect, persistentBit, connectToCAShare, modelHandleType, oplockLeaseType);

            Share_IsCA = (connectToCAShare == CAShareType.CAShare);

            Open = new HandleModelOpen();
            Open.IsConnectionExisted = true;
            Open.IsSessionExisted = true;

            if (oplockLeaseType == OplockLeaseType.LeaseV1)
            {
                Open.IsLeaseExisted = true;
                Open.LeaseVersion = 1;
            }
            else if (oplockLeaseType == OplockLeaseType.LeaseV2)
            {
                Open.IsLeaseExisted = true;
                Open.LeaseVersion = 2;
            }
            else if (oplockLeaseType == OplockLeaseType.BatchOplock)
            {
                Open.IsBatchOplockExisted = true;
            }

            if (modelHandleType == ModelHandleType.DurableHandleV1)
            {
                if (!Open.IsBatchOplockExisted && !Open.IsLeaseExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "3.3.5.9.6: If the RequestedOplockLevel field in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH and " +
                        "the create request does not include an SMB2_CREATE_REQUEST_LEASE create context with a LeaseState field that " +
                        "includes the SMB2_LEASE_HANDLE_CACHING bit value, " +
                        "the server MUST ignore this create context and skip this section.");
                    ModelHelper.Log(LogType.TestInfo, "This section is skipped.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    return;
                }

                ModelHelper.Log(LogType.Requirement, "3.3.5.9.6: In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to TRUE.");
                Open.IsDurable = true;
            }
            else if (modelHandleType == ModelHandleType.DurableHandleV2 || modelHandleType == ModelHandleType.PersistentHandle)
            {
                ModelHelper.Log(LogType.Requirement, "3.3.5.9.10: This section applies only to servers that implement the SMB 3.x dialect family. ");
                if (!ModelUtility.IsSmb3xFamily(Config.MaxSmbVersionSupported))
                {
                    ModelHelper.Log(LogType.TestInfo, "The server implements the dialect {0}.", Config.MaxSmbVersionSupported);
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    return;
                }

                if (modelHandleType != ModelHandleType.PersistentHandle && !Open.IsBatchOplockExisted && !Open.IsLeaseExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of this create context, " +
                        "if RequestedOplockLevel in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH, " +
                        "and if the create request does not include a SMB2_CREATE_REQUEST_LEASE or " +
                        "SMB2_CREATE_REQUEST_LEASE_V2 create context with a LeaseState field that includes SMB2_LEASE_HANDLE_CACHING, " +
                        "the server MUST ignore this create context and skip this section.");
                    ModelHelper.Log(LogType.TestInfo, "This section is skipped.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    return;
                }

                if (ModelUtility.IsSmb3xFamily(NegotiateDialect)
                    && persistentBit == PersistentBitType.PersistentBitSet
                    && Config.IsPersistentHandleSupported)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "3.3.5.4: The Capabilities field MUST be set to a combination of zero or more of the following bit values, as specified in section 2.2.4:");
                    ModelHelper.Log(LogType.Requirement,
                        "\tSMB2_GLOBAL_CAP_PERSISTENT_HANDLES if Connection.Dialect belongs to the SMB 3.x dialect family, " +
                        "SMB2_GLOBAL_CAP_PERSISTENT_HANDLES is set in the Capabilities field of the request, and the server supports persistent handles.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So SMB2_DHANDLE_FLAG_PERSISTENT bit is set in Connection.ServerCapabilities.");
                    ServerCapabilities_PersistentBitSet = true;
                }

                if (modelHandleType == ModelHandleType.PersistentHandle
                    && !(Share_IsCA && ServerCapabilities_PersistentBitSet))
                {
                    // TDI: if client asks for a persistent handle to a non CA share or
                    // Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_PERSISTENT_HANDLES
                    // The persistent handle is not granted.
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Share is not a CA share or Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_PERSISTENT_HANDLES.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    return;
                }

                ModelHelper.Log(LogType.Requirement, "In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to TRUE.");
                Open.IsDurable = true;

                if (modelHandleType == ModelHandleType.PersistentHandle && Share_IsCA && ServerCapabilities_PersistentBitSet)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "3.3.5.9.10: If the SMB2_DHANDLE_FLAG_PERSISTENT bit is set in the Flags field of the request, " +
                        "TreeConnect.Share.IsCA is TRUE, " +
                        "and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, " +
                        "the server MUST set Open.IsPersistent to TRUE.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So Open.IsPersistent is set to TRUE.");
                    Open.IsPersistent = true;
                }
            }
        }
        /// <summary>
        /// This method is used to verify the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context
        /// Cover TD section: 3.3.5.9.10
        /// Return true means the message is handled by this function. 
        /// Return false means the message needs further processing.        
        /// </summary>
        private static bool Handling_SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2_CreateContext(
            ModelSmb2Status status,
            ModelOpenFileRequest modelOpenFileRequest,
            DurableHandleResponseContext durableHandleResponseContext)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.9.10: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context");

            if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist
                || modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist
                || modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the create request also includes an SMB2_CREATE_DURABLE_HANDLE_REQUEST create context, " +
                    "or an SMB2_CREATE_DURABLE_HANDLE_RECONNECT or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 create context, " +
                    "the server MUST fail the create request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST is included.");
                if (modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT is included.");
                if (modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is included.");

                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                return true;
            }

            if (modelOpenFileRequest.durableV2RequestContext == DurableV2RequestContext.DurableV2RequestContextExistWithoutPersistent
                && modelOpenFileRequest.oplockLeaseType == OplockLeaseType.NoOplockOrLease)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of this create context, " +
                    "if RequestedOplockLevel in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH, " +
                    "and if the create request does not include a SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context  " +
                    "with a LeaseState field that includes SMB2_LEASE_HANDLE_CACHING, the server MUST ignore this create context and skip this section.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. ");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.NONE);
                return false;
            }

            if (Open != null
                && modelOpenFileRequest.isSameClient
                && modelOpenFileRequest.isSameCreateGuid)
            {
                ModelHelper.Log(LogType.Requirement,
                    "The server MUST locate the Open in GlobalOpenTable where Open.CreateGuid matches the CreateGuid in the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context, " +
                    "and Open.ClientGuid matches the ClientGuid of the connection that received this request.");
                ModelHelper.Log(LogType.TestInfo, "The Open is found.");

                ModelHelper.Log(LogType.Requirement,
                    "If an Open is found and the SMB2_FLAGS_REPLAY_OPERATION bit is not set in the SMB2 header, the server MUST fail the request with STATUS_DUPLICATE_OBJECTID.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_REPLAY_OPERATION is not set.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_DUPLICATE_OBJECTID);
                return true;
            }

            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If an Open is not found, the server MUST continue the create process specified in the \"Open Execution\" Phase, and perform the following additional steps:");
                Open = new HandleModelOpen();
                ModelHelper.Log(LogType.Requirement,
                    "In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE. ");
                Open.IsDurable = true;

                if (modelOpenFileRequest.durableV2RequestContext == DurableV2RequestContext.DurableV2RequestContextExistWithPersistent
                    && Share_IsCA
                    && ServerCapabilities_PersistentBitSet)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If the SMB2_DHANDLE_FLAG_PERSISTENT bit is set in the Flags field of the request, TreeConnect.Share.IsCA is TRUE, " +
                        "and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, the server MUST set Open.IsPersistent to TRUE.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. Open.IsPersistent is set to TRUE.");
                    Open.IsPersistent = true;
                }
            }

            if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextExistWithPersistent
                && modelOpenFileRequest.oplockLeaseType == OplockLeaseType.NoOplockOrLease)
            {
                ModelHelper.Log(LogType.Requirement,
                    "The server MUST skip the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context " +
                    "if the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the request and if neither of the following conditions are met:" +
                    "\tOpen.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH. " + "\tOpen.Lease.LeaseState has SMB2_LEASE_HANDLE_CACHING bit set.");
                ModelHelper.Log(LogType.TestInfo,
                    "All the above conditions are met. " +
                    "So the server skips the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context.");
                Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.NONE);
            }
            else
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.IsPersistent is TRUE, the server MUST set the SMB2_DHANDLE_FLAG_PERSISTENT bit in the Flags field. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsPersistent is {0}", Open.IsPersistent);
                if (Open.IsPersistent)
                {
                    Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2_WITH_PERSISTENT);
                }
            }
            return false;
        }