public void ReadConfig(out LeasingConfig c)
        {
            uncSharePath = Smb2Utility.GetUncPath(testConfig.SutIPAddress.ToString(), testConfig.BasicFileShare);

            c = new LeasingConfig
            {
                MaxSmbVersionSupported = ModelUtility.GetModelDialectRevision(testConfig.MaxSmbVersionSupported),
                IsLeasingSupported = testConfig.IsLeasingSupported,
                IsDirectoryLeasingSupported = testConfig.IsDirectoryLeasingSupported,
            };

            leasingConfig = c;

            Site.Log.Add(LogEntryKind.Debug, leasingConfig.ToString());
        }
        public void FileOperationToBreakLeaseRequest(FileOperation operation, OperatorType operatorType, ModelDialectRevision dialect, out LeasingConfig c)
        {
            c = leasingConfig;

            LeasingClientInfo clientInfo = clients[(int)operatorType];

            // Avoid to fail because Windows issue
            if (dialect == ModelDialectRevision.Smb2002)
            {
                clientInfo.ClientGuid = Guid.NewGuid();
            }

            if (!clientInfo.IsInitialized)
            {
                InitializeClient(clientInfo, dialect);
            }

            if (operation == FileOperation.WRITE_DATA)
            {
                #region WRITE_DATA

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN_IF,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                byte[] data = Encoding.ASCII.GetBytes("Write data to break READ caching.");
                ushort creditCharge = Smb2Utility.CalculateCreditCharge((uint)data.Length, ModelUtility.GetDialectRevision(dialect));

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.WriteRequest(creditCharge, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId,
                    0, clientInfo.FileId, Channel_Values.CHANNEL_NONE, WRITE_Request_Flags_Values.None, new byte[0], data);
                clientInfo.MessageId += (ulong)creditCharge;

                #endregion
            }
            else if (operation == FileOperation.SIZE_CHANGED)
            {
                #region SIZE_CHANGED

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                FileEndOfFileInformation changeSizeInfo;
                changeSizeInfo.EndOfFile = 512;

                byte[] inputBuffer;
                inputBuffer = TypeMarshal.ToBytes<FileEndOfFileInformation>(changeSizeInfo);

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.SetInfoRequest(
                    1,
                    1,
                    clientInfo.Flags,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    clientInfo.TreeId,
                    SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE,
                    (byte)FileInformationClasses.FileEndOfFileInformation,
                    SET_INFO_Request_AdditionalInformation_Values.NONE,
                    clientInfo.FileId,
                    inputBuffer);

                #endregion
            }
            else if (operation == FileOperation.RANGE_LOCK)
            {
                #region RANGE_LOCK

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                clientInfo.Locks = new LOCK_ELEMENT[1];
                clientInfo.LockSequence = 0;
                clientInfo.Locks[0].Offset = 0;
                clientInfo.Locks[0].Length = (ulong)1 * 1024 / 2;
                clientInfo.Locks[0].Flags = LOCK_ELEMENT_Flags_Values.LOCKFLAG_SHARED_LOCK;

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.LockRequest(
                    1,
                    1,
                    clientInfo.Flags,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    clientInfo.TreeId,
                    clientInfo.LockSequence++,
                    clientInfo.FileId,
                    clientInfo.Locks
                    );

                #endregion
            }
            else if (operation == FileOperation.OPEN_OVERWRITE)
            {
                #region OPEN_OVERWRITE
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OVERWRITE,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                    clientInfo.CreateContexts);

                #endregion
            }
            else if (operation == FileOperation.OPEN_WITHOUT_OVERWRITE)
            {
                #region OPEN_WITHOUT_OVERWRITE
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                if (!clientInfo.IsOpened)
                {
                    clientInfo.LastOperationMessageId = clientInfo.MessageId;
                    clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts);
                }

                #endregion
            }
            else if (operation == FileOperation.OPEN_SHARING_VIOLATION)
            {
                #region OPEN_SHARING_VIOLATION
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                if (!clientInfo.IsOpened)
                {
                    clientInfo.LastOperationMessageId = clientInfo.MessageId;
                    clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts);
                }
                #endregion
            }
            else if (operation == FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE)
            {
                #region OPEN_SHARING_VIOLATION_WITH_OVERWRITE
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                if (!clientInfo.IsOpened)
                {
                    clientInfo.LastOperationMessageId = clientInfo.MessageId;
                    clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OVERWRITE,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts);
                }

                #endregion
            }
            else if (operation == FileOperation.DELETED)
            {
                #region DELETED
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        (originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE) | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                FileDispositionInformation deleteInfo;
                deleteInfo.DeletePending = 1;

                byte[] inputBuffer;
                inputBuffer = TypeMarshal.ToBytes<FileDispositionInformation>(deleteInfo);

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.SetInfoRequest(
                    1,
                    1,
                    clientInfo.Flags,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    clientInfo.TreeId,
                    SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE,
                    (byte)FileInformationClasses.FileDispositionInformation,
                    SET_INFO_Request_AdditionalInformation_Values.NONE,
                    clientInfo.FileId,
                    inputBuffer);
                #endregion
            }
            else if (operation == FileOperation.RENAMEED)
            {
                #region RENAMEED
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                        clientInfo.CreateContexts,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                string newFileName = originalClient.ParentDirectory + "\\" + Guid.NewGuid().ToString();
                FileRenameInformation info = new FileRenameInformation();
                info.ReplaceIfExists = 1;
                info.FileName = ConvertStringToByteArray(newFileName);
                info.FileNameLength = (uint)info.FileName.Length;
                info.RootDirectory = FileRenameInformation_RootDirectory_Values.V1;
                info.Reserved = new byte[7];

                byte[] inputBuffer;
                inputBuffer = TypeMarshal.ToBytes<FileRenameInformation>(info);

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.SetInfoRequest(
                    1,
                    1,
                    clientInfo.Flags,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    clientInfo.TreeId,
                    SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE,
                    (byte)FileInformationClasses.FileRenameInformation,
                    SET_INFO_Request_AdditionalInformation_Values.NONE,
                    clientInfo.FileId,
                    inputBuffer);

                originalClient.File = newFileName;
                #endregion
            }
            else if (operation == FileOperation.PARENT_DIR_RENAMED)
            {
                #region PARENT_DIR_RENAMED
                if (clientInfo.IsOpened)
                {
                    clientInfo.Reset(operatorType == OperatorType.SecondClient);

                    InitializeClient(clientInfo, dialect);
                }

                uint status = Smb2Status.STATUS_SUCCESS;

                Packet_Header header;
                CREATE_Response createResponse;
                Smb2CreateContextResponse[] serverCreateContexts;

                if (!clientInfo.IsOpened)
                {
                    status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.ParentDirectory,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        CreateOptions_Values.FILE_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        null,
                        out clientInfo.FileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse);
                    Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds.");
                }

                string newFileName = "LeasingDir_" + Guid.NewGuid().ToString();
                FileRenameInformation info = new FileRenameInformation();
                info.ReplaceIfExists = 0;
                info.FileName = ConvertStringToByteArray(newFileName);
                info.FileNameLength = (uint)info.FileName.Length;
                info.RootDirectory = FileRenameInformation_RootDirectory_Values.V1;
                info.Reserved = new byte[7];

                byte[] inputBuffer;
                inputBuffer = TypeMarshal.ToBytes<FileRenameInformation>(info);

                clientInfo.LastOperationMessageId = clientInfo.MessageId;
                clientInfo.Client.SetInfoRequest(
                    1,
                    1,
                    clientInfo.Flags,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    clientInfo.TreeId,
                    SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE,
                    (byte)FileInformationClasses.FileRenameInformation,
                    SET_INFO_Request_AdditionalInformation_Values.NONE,
                    clientInfo.FileId,
                    inputBuffer);
                // Does not need to update these two fields File and ParentDirectory in orginal client because the operation will fail.
                #endregion
            }

            lastOperation = new BreakOperation(operation, operatorType);
        }
        public static void FileOperationToBreakLeaseRequestReturn(LeasingConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            ModelFileOperationRequest fileOperationRequest = ModelHelper.RetrieveOutstandingRequest<ModelFileOperationRequest>(ref request);

            Condition.IsFalse(negotiateDialect == DialectRevision.Smb2002);

            Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);
            Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported);

            Condition.IsTrue(c.IsLeasingSupported || c.IsDirectoryLeasingSupported);
            Condition.IsTrue(config.MaxSmbVersionSupported == c.MaxSmbVersionSupported);

            // 3.3.1.4   Algorithm for Leasing in an Object Store
            smb2Lease.BreakToLeaseState = smb2Lease.LeaseState;

            if (fileOperationRequest.OptorType != OperatorType.SameClientId)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.1.4: READ caching permits the SMB2 client to cache data read from the object. Before processing one of the following operations from a client with a different ClientId, " +
                    "the object store MUST request that the server revoke READ caching. The object store is not required to wait for acknowledgment:");

                if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING) != 0
                        && ((fileOperationRequest.Operation == FileOperation.OPEN_OVERWRITE)
                            || (fileOperationRequest.Operation == FileOperation.WRITE_DATA)
                            || (fileOperationRequest.Operation == FileOperation.SIZE_CHANGED)
                            || (fileOperationRequest.Operation == FileOperation.RANGE_LOCK)))
                {
                    ModelHelper.Log(LogType.Requirement,
                        "READ caching on a file:");
                    ModelHelper.Log(LogType.Requirement,
                        "\tThe file is opened in a manner that overwrites the existing file.");
                    ModelHelper.Log(LogType.Requirement,
                        "\tData is written to the file.");
                    ModelHelper.Log(LogType.Requirement,
                        "\tThe file size is changed.");
                    ModelHelper.Log(LogType.Requirement,
                        "\tA byte range lock is requested for the file.");

                    ModelHelper.Log(LogType.TestInfo, "READ caching lease state is broken.");
                    smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_READ_CACHING;
                }
            }

            if (fileOperationRequest.OptorType != OperatorType.SameClientId)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "WRITE caching permits the SMB2 client to cache writes and byte-range locks on an object. " +
                    "Before processing one of the following operations, the underlying object store MUST request that the server revoke WRITE caching, " +
                    "and the object store MUST wait for acknowledgment from the server before proceeding with the operation:");

                if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0
                        && fileOperationRequest.Operation != FileOperation.OPEN_SHARING_VIOLATION
                        && fileOperationRequest.Operation != FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE
                        && fileOperationRequest.Operation != FileOperation.PARENT_DIR_RENAMED)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "The file is opened by a local application or via another protocol, " +
                        "or opened via SMB2 without providing the same ClientId, and requested access includes any flags other than FILE_READ_ATTRIBUTES, " +
                        "FILE_WRITE_ATTRIBUTES, and SYNCHRONIZE.");
                    ModelHelper.Log(
                        LogType.TestInfo, "WRITE caching lease state is broken.");
                    smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING;
                }

                ModelHelper.Log(
                    LogType.Requirement,
                    "HANDLE caching permits one or more SMB2 clients to delay closing handles it holds open, " +
                    "or to defer sending opens. Before processing one of the following operations, " +
                    "the underlying object store MUST request that the server revoke HANDLE caching, " +
                    "and the object store MUST wait for acknowledgment before proceeding with the operation:");
                if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING) != 0
                        && (fileOperationRequest.Operation == FileOperation.OPEN_SHARING_VIOLATION
                            || fileOperationRequest.Operation == FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE
                            || fileOperationRequest.Operation == FileOperation.RENAMEED || fileOperationRequest.Operation == FileOperation.DELETED
                            || fileOperationRequest.Operation == FileOperation.PARENT_DIR_RENAMED))
                {
                    ModelHelper.Log(LogType.Requirement, "HANDLE caching on a file:");
                    ModelHelper.Log(
                        LogType.Requirement,
                        "\tA file is opened with an access or share mode incompatible with opens from different ClientIds " +
                        "or local applications as described in [MS-FSA] section 2.1.5.1.2.");
                    ModelHelper.Log(LogType.Requirement, "\tThe parent directory is being renamed.");

                    ModelHelper.Log(
                        LogType.TestInfo, "HANDLE caching lease state is broken.");
                    smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING;
                }
            }

            // HANDLE caching permits one or more SMB2 clients to delay closing handles it holds open, or to defer sending opens.
            // Before processing one of the following operations, the underlying object store MUST request that the server revoke HANDLE caching,
            // and the object store MUST wait for acknowledgment before proceeding with the operation:
            //      The parent directory is being renamed.
            if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING) != 0
                    && fileOperationRequest.Operation == FileOperation.PARENT_DIR_RENAMED)
            {
                smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING;
            }

            if (smb2Lease.BreakToLeaseState != smb2Lease.LeaseState)
            {
                if (smb2Lease.LeaseState != (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING)
                {
                    // 3.3.4.7   Object Store Indicates a Lease Break
                    // The server MUST set Lease.Breaking to TRUE
                    ModelHelper.Log(LogType.TestInfo, "Lease.Breaking is set to TRUE.");
                    smb2Lease.Breaking = true;
                }

                // 3.3.4.7   Object Store Indicates a Lease Break
                if (ModelUtility.IsSmb3xFamily(c.MaxSmbVersionSupported) && smb2Lease.Version == 2)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.4.7: If the server implements the SMB 3.x dialect family and Lease.Version is 2, the server MUST set NewEpoch to Lease.Epoch + 1. ");
                    ModelHelper.Log(LogType.TestInfo, "The server implements the SMB 3.x dialect family and Lease.Version is 2.");
                    smb2Lease.Epoch++;
                }

                // 3.3.1.4   Algorithm for Leasing in an Object Store
                // The algorithm SHOULD support the following combinations of caching flags on a file:
                // No caching, Read caching, Read + Write caching, Read + Handle caching, and Read + Write + Handle caching.
                if ((smb2Lease.BreakToLeaseState & (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING) == 0)
                {
                    ModelHelper.Log(LogType.TestInfo, "Lease state is set to No caching.");
                    smb2Lease.BreakToLeaseState = 0;
                }
            }
        }
        public static void ReadConfigReturn(LeasingConfig c)
        {
            Condition.IsTrue(state == ModelState.Uninitialized);
            Condition.IsNotNull(c);

            Condition.IsTrue(c.MaxSmbVersionSupported == ModelDialectRevision.Smb2002
                || c.MaxSmbVersionSupported == ModelDialectRevision.Smb21
                || c.MaxSmbVersionSupported == ModelDialectRevision.Smb30
                || c.MaxSmbVersionSupported == ModelDialectRevision.Smb302);
            if (c.MaxSmbVersionSupported == ModelDialectRevision.Smb2002)
            {
                Condition.IsFalse(c.IsDirectoryLeasingSupported);
                Condition.IsFalse(c.IsLeasingSupported);
            }
            else if (c.MaxSmbVersionSupported == ModelDialectRevision.Smb21)
            {
                Condition.IsFalse(c.IsDirectoryLeasingSupported);
            }

            config = c;

            state = ModelState.Initialized;
        }
        public static void CreateResponse(ModelSmb2Status status, ReturnLeaseContextType returnLeaseContextType, uint leaseState, 
            LeaseFlagsValues leaseFlags, LeasingConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            ModelCreateLeaseRequest createRequest = ModelHelper.RetrieveOutstandingRequest<ModelCreateLeaseRequest>(ref request);

            Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);
            Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported);

            if (!c.IsLeasingSupported)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server does not support leasing and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST ignore the \"RqLs\" create context.");
                ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
                return;
            }

            if ((negotiateDialect == DialectRevision.Smb21 || Smb2Utility.IsSmb3xFamily(negotiateDialect))
                && c.IsLeasingSupported
                && (createRequest.ContextType == LeaseContextType.LeaseV1)) // the DataLength field equals 0x20
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect is \"2.100\" or belongs to the \"3.x\" dialect family, and the DataLength field equals 0x20, " +
                        "the server MUST attempt to acquire a lease on the open from the underlying object store as described in section 3.3.5.9.8.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.8   Handling the SMB2_CREATE_REQUEST_LEASE Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLease requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLease;

                smb2Lease = new Smb2Lease();
                if (Smb2Utility.IsSmb3xFamily(negotiateDialect))
                {
                    ModelHelper.Log(LogType.Requirement, "3.3.5.9.8: If Connection.Dialect belongs to the SMB 3.x dialect family, Lease.Version is set to 1.");
                    smb2Lease.Version = 1;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.");
                    ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                    //If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.
                    smb2Lease.LeaseState = requestLease.LeaseState;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && c.IsLeasingSupported
                && (createRequest.ContextType == LeaseContextType.LeaseV2)) // the DataLength field equals 0x34
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect belongs to the \"3.x\" dialect family, and the DataLength field equals 0x34, " +
                    "the server MUST attempt to acquire a lease on the open from the underlying object store, as described in section 3.3.5.9.11.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.11   Handling the SMB2_CREATE_REQUEST_LEASE_V2 Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE_V2
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLeaseV2 requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLeaseV2;

                smb2Lease = new Smb2Lease(2);

                // To reduce parameters and states, use CreateOptions instead of FileAttributes here, as we assume settings in CreateOptions and FileAtributes are consistent.
                if (createRequest.CreateOptions.HasFlag(CreateOptions_Values.FILE_DIRECTORY_FILE)
                    && (requestLease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If the FileAttributes field in the request indicates that this operation is on a directory and " +
                        "LeaseState includes SMB2_LEASE_WRITE_CACHING, the server MUST clear the bit SMB2_LEASE_WRITE_CACHING in the LeaseState field.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_WRITE_CACHING is cleared.");
                    requestLease.LeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.<271> " +
                        "If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.");
                    smb2Lease.LeaseState = requestLease.LeaseState;
                    // The server MUST increment Lease.Epoch by 1.
                    ModelHelper.Log(LogType.TestInfo, "Lease.Epoch is incremented by 1.");
                    smb2Lease.Epoch++;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);

                if (requestLease.LeaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET))
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set in the Flags field of the request, " +
                        "ParentLeaseKey MUST be set to the ParentLeaseKey in the request and SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit MUST be set in the Flags field of the response.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set.");
                    Condition.IsTrue(leaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET));
                }
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
            Condition.IsTrue(leaseState == (uint)LeaseStateValues.SMB2_LEASE_NONE);
            Condition.IsTrue(leaseFlags == LeaseFlagsValues.NONE);
            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }