/// <summary>
        /// Write file content over RDMA. The file content will be writen with specific number of operations.
        /// The total size of the write content is SMB2 negotiated MaxWriteize, so content size
        /// in each SMB2 WRITE request is ( MaxWriteSize / operationCount )
        /// </summary>
        /// <param name="operationCount">count of SMB2 WRITE operation</param>
        public void WriteOverRdma(uint operationCount = 1)
        {
            string fileName = CreateRandomFileName();

            InitSmbdConnectionForTestCases(fileName);

            uint writeSize = smbdAdapter.Smb2MaxWriteSize / operationCount;
            uint totalSize = writeSize * operationCount;

            // SMB2 Write file
            byte[] fileContent = Encoding.ASCII.GetBytes(Smb2Utility.CreateRandomStringInByte((int)writeSize));

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Send each write request according SMB2 write file limit.");
            for (int i = 0; i < operationCount; ++i)
            {
                // register memory and get buffer descriptor
                SmbdBufferDescriptorV1 descp;
                smbdAdapter.SmbdRegisterBuffer(
                    writeSize,
                    SmbdBufferReadWrite.RDMA_READ_PERMISSION_FOR_WRITE_FILE,
                    out descp
                    );
                smbdAdapter.SmbdWriteRegisteredBuffer(fileContent, descp);
                byte[] channelInfo = TypeMarshal.ToBytes <SmbdBufferDescriptorV1>(descp);

                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Write content to file over RDMA.");
                WRITE_Response writeResponse;
                NtStatus       status = (NtStatus)smbdAdapter.Smb2WriteOverRdmaChannel(
                    (UInt64)i * writeSize,
                    channelInfo,
                    writeSize,
                    out writeResponse
                    );
                BaseTestSite.Assert.AreEqual <NtStatus>(
                    NtStatus.STATUS_SUCCESS,
                    status,
                    "Status of SMB2 Write File offset {0} is {1}", i * writeSize, status);
                BaseTestSite.Assert.AreEqual <uint>(
                    (uint)writeSize,
                    writeResponse.Count,
                    "DataLength in WRITE response is {0}", writeResponse.Count);
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Validate file content.");
            ValidateFileContent(fileContent, totalSize);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Close file.");
            smbdAdapter.Smb2CloseFile();
        }
Example #2
0
        public void BVT_Smb2OverRdma_Smb302_Write_SMB2_CHANNEL_RDMA_V1_INVALIDATE()
        {
            EstablishConnectionAndOpenFile(fileName, Smb302AboveDialects);

            uint writeSize = smbdAdapter.Smb2MaxWriteSize;

            byte[] fileContent = Smb2Utility.CreateRandomByteArray((int)writeSize);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register memory and get buffer descriptor for SMB2 WRITE");
            SmbdBufferDescriptorV1 descp;
            NtStatus status = smbdAdapter.SmbdRegisterBuffer(
                writeSize,
                SmbdBufferReadWrite.RDMA_READ_PERMISSION_FOR_WRITE_FILE,
                out descp);

            BaseTestSite.Assert.AreEqual(
                NtStatus.STATUS_SUCCESS,
                status,
                "Register buffer should succeed.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Write content to file over RDMA.");
            status = Smb2WriteOverRdma(fileName, fileContent, Channel_Values.CHANNEL_RDMA_V1_INVALIDATE, descp);
            BaseTestSite.Assert.AreEqual <NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "SMB2 WRITE over RDMA should succeed.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify file content.");
            ValidateFileContent(fileContent);

            try
            {
                fileContent = Encoding.ASCII.GetBytes(Smb2Utility.CreateRandomStringInByte((int)writeSize));

                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Send Smb2 WRITE request using same descriptor which should be invalidated.");
                status = Smb2WriteOverRdma(fileName, fileContent, Channel_Values.CHANNEL_RDMA_V1_INVALIDATE, descp);
            }
            catch
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Verify connection is terminated .");
                smbdAdapter.WaitRdmaDisconnect();
            }

            BaseTestSite.Assert.IsFalse(smbdAdapter.ClientConnection.Endpoint.IsConnected, "Connection should be terminated when accessing a memory window which is already invalidated.");
        }
Example #3
0
        public void Smb2OverRdma_Write_SMB2_CHANNEL_RDMA_V1()
        {
            EstablishConnectionAndOpenFile(fileName);

            uint writeSize = smbdAdapter.Smb2MaxWriteSize;

            byte[] fileContent = Smb2Utility.CreateRandomByteArray((int)writeSize);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register memory and get buffer descriptor for SMB2 WRITE");
            SmbdBufferDescriptorV1 descp;
            NtStatus status = smbdAdapter.SmbdRegisterBuffer(
                writeSize,
                SmbdBufferReadWrite.RDMA_READ_PERMISSION_FOR_WRITE_FILE,
                out descp);

            BaseTestSite.Assert.AreEqual(
                NtStatus.STATUS_SUCCESS,
                status,
                "Register buffer should succeed.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Write content to file over RDMA.");
            status = Smb2WriteOverRdma(fileName, fileContent, Channel_Values.CHANNEL_RDMA_V1, descp);
            BaseTestSite.Assert.AreEqual <NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "SMB2 WRITE over RDMA should succeed.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify file content.");
            ValidateFileContent(fileContent);

            fileContent = Encoding.ASCII.GetBytes(Smb2Utility.CreateRandomStringInByte((int)writeSize));

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Send Smb2 WRITE request using same descriptor.");
            status = Smb2WriteOverRdma(fileName, fileContent, Channel_Values.CHANNEL_RDMA_V1, descp);

            BaseTestSite.Assert.AreEqual <NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "SMB2 WRITE over RDMA should succeed.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify file content.");
            ValidateFileContent(fileContent);
        }
Example #4
0
        /// <summary>
        /// Write from Main channel over TCP
        /// </summary>
        /// <param name="serverIp">IP Address of Server.</param>
        /// <param name="clientIp">IP Address of Client.</param>
        /// <param name="fileName">File name.</param>
        /// <param name="totalWriteSize">Total Write Size in Bytes.</param>
        /// <param name="content">Content in the WRITE request.</param>
        /// <param name="treeId">Tree Connect Id.</param>
        /// <param name="fileId">File Id.</param>
        private void WriteFromMainChannel(
            IPAddress serverIp,
            IPAddress clientIp,
            string fileName,
            uint totalWriteSize,
            out byte[] content,
            out uint treeId,
            out FILEID fileId
            )
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Write file from Main channel over TCP.");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "serverIp: " + serverIp.ToString());
            BaseTestSite.Log.Add(LogEntryKind.Debug, "clientIp: " + clientIp.ToString());
            BaseTestSite.Log.Add(LogEntryKind.Debug, "fileName: " + fileName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Total write size in Bytes: " + totalWriteSize.ToString());

            mainChannelClient.ConnectOverTCP(serverIp, clientIp);

            // SMB2 Negotiate
            DialectRevision[] negotiatedDialects = new DialectRevision[] { DialectRevision.Smb30, DialectRevision.Smb2002, DialectRevision.Smb21 };
            DialectRevision   selectedDialect;
            NtStatus          status = (NtStatus)mainChannelClient.Smb2Negotiate(negotiatedDialects, out selectedDialect);

            BaseTestSite.Assert.AreEqual <NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Negotiate is {0}", status);


            // SMB2 Session Setup
            status = (NtStatus)mainChannelClient.Smb2SessionSetup(
                testConfig.SecurityPackageForSmb2UserAuthentication,
                testConfig.DomainName,
                testConfig.UserName,
                testConfig.Password,
                testConfig.ServerName
                );
            BaseTestSite.Assert.AreEqual <NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Session Setup is {0}", status);
            // SMB2 Tree Connect
            status = (NtStatus)mainChannelClient.Smb2TreeConnect(testConfig.ServerName,
                                                                 testConfig.ShareFolder);
            BaseTestSite.Assert.AreEqual <NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Tree Connect is {0}", status);

            // SMB2 Open File
            status = (NtStatus)mainChannelClient.Smb2Create(fileName);
            BaseTestSite.Assert.AreEqual <NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Create is {0}", status);

            uint maxWriteSize = mainChannelClient.Smb2MaxWriteSize;

            content = Encoding.ASCII.GetBytes(Smb2Utility.CreateRandomStringInByte((int)totalWriteSize));

            #region SMB2 Write file
            // Send each write request according SMB2 write file limit
            uint offset = 0;
            while (offset < totalWriteSize)
            {
                uint length = maxWriteSize;
                if (offset + length > content.Length)
                {
                    length = (uint)content.Length - offset;
                }

                WRITE_Response writeResponse;
                status = (NtStatus)mainChannelClient.Smb2Write((UInt64)offset, content, out writeResponse);
                BaseTestSite.Assert.AreEqual <NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Write File is {0}", status);
                BaseTestSite.Assert.AreEqual <uint>((uint)length, writeResponse.Count, "DataLength in WRITE response is {0}", writeResponse.Count);

                offset += length;
            }
            #endregion

            treeId = mainChannelClient.TreeId;
            fileId = mainChannelClient.FileId;
        }
        public void BVT_MultiCredit_OneRequestWithMultiCredit()
        {
            TestConfig.CheckDialect(DialectRevision.Smb21);
            TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LARGE_MTU);

            Guid   clientGuid = Guid.NewGuid();
            string fileName   = "MultiCredit_" + clientGuid.ToString() + ".txt";

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: 1. NEGOTIATE; 2. SESSION_SETUP; 3. TREE_CONNECT");
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            client.ConnectToServerOverTCP(TestConfig.SutIPAddress);
            Capabilities_Values clientCapabilities = Capabilities_Values.GLOBAL_CAP_LARGE_MTU;

            client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: clientCapabilities);
            client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            uint treeId;

            client.TreeConnect(uncSharePath, out treeId);

            int    bufferSize = (int)client.MaxBufferSize;
            FILEID fileId;

            Smb2CreateContextResponse[] serverCreateContexts;
            ushort grantedCredit = 0;

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request with {0} credits", client.Credits);
            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts,
                checker: (header, response) =>
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    header.Status,
                    "{0} should succeed, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));

                BaseTestSite.Log.Add(LogEntryKind.Debug,
                                     "The MaxBufferSize of the server is {0}.",
                                     client.MaxBufferSize);
                BaseTestSite.Log.Add(LogEntryKind.Debug,
                                     "Server has granted {0} credits to the client.",
                                     client.Credits);

                // Make sure client hold enough credits for test
                ushort maxBufferSizeInCredit = (ushort)((client.MaxBufferSize - 1) / 65536 + 1);
                if (client.Credits < maxBufferSizeInCredit)
                {
                    if (client.Credits < 2)
                    {
                        BaseTestSite.Assert.Inconclusive(
                            "This test case is not applicable when the server only grants {0} credits",
                            client.Credits);
                    }
                    // Test max buffer according to granted credits.
                    bufferSize = (client.Credits - 1) * 65536;
                }

                grantedCredit = header.CreditRequestResponse;
            });

            contentWrite = Smb2Utility.CreateRandomStringInByte(bufferSize);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client attempts to write {0} bytes content to file when server grants {1} credits",
                client.MaxBufferSize, client.Credits);

            client.Write(
                treeId,
                fileId,
                contentWrite,
                checker: (header, response) =>
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    header.Status,
                    "{0} should succeed, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));

                grantedCredit = header.CreditRequestResponse;
            });

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client attempts to read {0} bytes content from file when server grants {1} credit",
                bufferSize, client.Credits);
            client.Read(treeId, fileId, 0, (uint)contentWrite.Length, out contentRead);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: 1. CLOSE; 2. TREE_DISCONNECT; 3. LOG_OFF; 4. DISCONNECT");
            client.Close(treeId, fileId);
            client.TreeDisconnect(treeId);
            client.LogOff();
            client.Disconnect();
        }
Example #6
0
        private void CreateFile(string uncShare, string fileName, int lengthInByte)
        {
            Site.Log.Add(
                LogEntryKind.Debug,
                "Create file {0} in share {1}", fileName, uncShare);

            Smb2FunctionalClient client = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);

            client.ConnectToServer(testConfig.UnderlyingTransport, testConfig.SutComputerName, testConfig.SutIPAddress);

            client.CreditGoal = 32;

            client.Negotiate(
                new DialectRevision[] { ModelUtility.GetDialectRevision(config.MaxSmbVersionSupported) },
                testConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_LARGE_MTU);

            client.SessionSetup(
                testConfig.DefaultSecurityPackage,
                testConfig.SutComputerName,
                testConfig.AccountCredential,
                testConfig.UseServerGssToken);

            uint tId;

            client.TreeConnect(
                uncShare,
                out tId);

            Smb2CreateContextResponse[] serverCreateContexts;
            FILEID fId;

            client.Create(
                tId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fId,
                out serverCreateContexts);

            string content;

            if (isMultiCreditSupportedOnConnection)
            {
                content = Smb2Utility.CreateRandomStringInByte(lengthInByte);
                client.Write(tId, fId, content);
            }
            else
            {
                // Write several times if server does not support multi credit
                int   writeTimes = lengthInByte / (64 * 1024);
                int   rest       = lengthInByte % (64 * 1024);
                ulong offset     = 0;

                for (int time = 0; time < writeTimes; time++)
                {
                    content = Smb2Utility.CreateRandomString(64);
                    client.Write(tId, fId, content, offset);
                    offset += 64 * 1024;
                }

                if (rest != 0)
                {
                    content = Smb2Utility.CreateRandomStringInByte(rest);
                    client.Write(tId, fId, content, offset);
                }
            }

            client.Close(tId, fId);

            client.TreeDisconnect(tId);

            client.LogOff();

            client.Disconnect();

            Site.Log.Add(
                LogEntryKind.Debug,
                "Create file {0} in share {1}", fileName, uncShare);
        }
Example #7
0
        public void CreditOperationRequest(
            ModelMidType midType,
            ModelCreditCharge creditCharge,
            ModelCreditRequestNum creditRequestNum,
            ModelPayloadSize payloadSize,
            ModelPayloadType payloadType)
        {
            #region Customize message id

            ulong smallestAvailableMId = testClient.SequenceWindow.Min;
            ulong largestAvailableMId  = testClient.SequenceWindow.Max;
            ulong customizedMId        = 0;

            switch (midType)
            {
            case ModelMidType.UnavailableMid:
            {
                customizedMId = largestAvailableMId + 1;
                break;
            }

            case ModelMidType.UsedMid:
            {
                customizedMId = smallestAvailableMId - 1;
                break;
            }

            case ModelMidType.ValidMid:
            {
                customizedMId = (ulong)(smallestAvailableMId + largestAvailableMId) / 2;
                break;
            }

            default:
                throw new ArgumentException("midType");
            }

            testClient.GenerateMessageId = (sequenceWindow) => customizedMId;

            Site.Log.Add(
                LogEntryKind.Debug,
                "*****customizedMId = {0}", customizedMId);

            #endregion

            #region Customize credit charge

            ushort customizedCreditCharge = 0;
            // Only customize credit charge when midType is valid
            if (midType == ModelMidType.ValidMid)
            {
                switch (creditCharge)
                {
                case ModelCreditCharge.CreditChargeWithinBoundary:
                {
                    customizedCreditCharge = (ushort)((largestAvailableMId - customizedMId + 2) / 2);
                    break;
                }

                case ModelCreditCharge.CreditChargeExceedBoundary:
                {
                    customizedCreditCharge = (ushort)(largestAvailableMId - customizedMId + 2);
                    break;
                }

                case ModelCreditCharge.CreditChargeSetZero:
                {
                    customizedCreditCharge = 0;
                    break;
                }

                default:
                {
                    Site.Assume.Fail("Unexpected creditCharge {0}", creditCharge);
                    break;
                }
                }
            }

            testClient.GenerateCreditCharge = (size) => customizedCreditCharge;

            Site.Log.Add(
                LogEntryKind.Debug,
                "*****customizedCreditCharge = {0}", customizedCreditCharge);

            #endregion

            #region Customize credit request

            ushort customizedCreditRequest = 0;
            switch (creditRequestNum)
            {
            case ModelCreditRequestNum.CreditRequestSetNonZero:
            {
                customizedCreditRequest = (ushort)((1 + testClient.CreditGoal) / 2);
                break;
            }

            case ModelCreditRequestNum.CreditRequestSetZero:
            {
                customizedCreditRequest = 0;
                break;
            }

            default:
            {
                Site.Assume.Fail("Unexpected creditRequestNum {0}", creditRequestNum);
                break;
            }
            }

            testClient.GenerateCreditRequest = (sequeceWindow, creditGoal, charge) => customizedCreditRequest;

            Site.Log.Add(
                LogEntryKind.Debug,
                "*****customizedCreditRequest = {0}", customizedCreditRequest);

            #endregion

            #region Calculate payload size

            int dataLengthInByte = 0;
            switch (payloadSize)
            {
            case ModelPayloadSize.PayloadSizeEqualToBoundary:
            {
                if (customizedCreditCharge == 0 && isMultiCreditSupportedOnConnection)
                {
                    dataLengthInByte = 64 * 1024;
                }
                else if (!isMultiCreditSupportedOnConnection)
                {
                    //3.3.5.2: If Connection.SupportsMultiCredit is FALSE and the size of the request is greater than 68*1024 bytes, the server SHOULD<200> terminate the connection
                    //Note 1. 68*1024 byte is total size of Smb2 packet including header, so need to subtract such overhead to calculate payload size
                    //     2. This case is only for WRITE but here does not distiguish READ and WRITE for simplicity

                    uint maxSize = 0;
                    if (testConfig.UnderlyingTransport == Smb2TransportType.NetBios)
                    {
                        maxSize = MaxNetbiosBufferSize;
                    }
                    else
                    {
                        maxSize = 68 * 1024;
                    }

                    dataLengthInByte = (int)(maxSize - Smb2PacketHeaderSizeInByte - Smb2WriteRequestBodySizeInByte);
                }
                else
                {
                    dataLengthInByte = customizedCreditCharge * 64 * 1024;
                }
                break;
            }

            case ModelPayloadSize.PayloadSizeLargerThanBoundary:
            {
                if (customizedCreditCharge == 0 && isMultiCreditSupportedOnConnection)
                {
                    dataLengthInByte = 64 * 1024 + 1;
                }
                else if (!isMultiCreditSupportedOnConnection)
                {
                    //3.3.5.2: If Connection.SupportsMultiCredit is FALSE and the size of the request is greater than 68*1024 bytes, the server SHOULD<200> terminate the connection
                    //Note 1. 68*1024 byte is total size of Smb2 packet including header, so need to subtract such overhead to calculate payload size
                    //     2. This case is only for WRITE but here does not distiguish READ and WRITE for simplicity

                    uint maxSize = 0;
                    if (testConfig.UnderlyingTransport == Smb2TransportType.NetBios)
                    {
                        maxSize = MaxNetbiosBufferSize;
                    }
                    else
                    {
                        maxSize = 68 * 1024;
                    }
                    dataLengthInByte = (int)(maxSize - Smb2PacketHeaderSizeInByte - Smb2WriteRequestBodySizeInByte + 1);
                }
                else
                {
                    dataLengthInByte = customizedCreditCharge * 64 * 1024 + 1;
                }
                break;
            }

            case ModelPayloadSize.PayloadSizeLessThanBoundary:
            {
                if (customizedCreditCharge == 0 && isMultiCreditSupportedOnConnection)
                {
                    dataLengthInByte = 32 * 1024;
                }
                else if (!isMultiCreditSupportedOnConnection)
                {
                    dataLengthInByte = 34 * 1024;
                }
                else
                {
                    dataLengthInByte = customizedCreditCharge * 32 * 1024;
                }
                break;
            }

            default:
            {
                Site.Assume.Fail("Unexpected creditRequestNum {0}", creditRequestNum);
                break;
            }
            }

            Site.Log.Add(
                LogEntryKind.Debug,
                "*****dataLengthInByte = {0}", dataLengthInByte);

            #endregion

            #region Send request

            uint status         = 0;
            uint creditResponse = 0;

            switch (payloadType)
            {
            case ModelPayloadType.RequestPayload:
            {
                try
                {
                    string contentToWrite = Smb2Utility.CreateRandomStringInByte(dataLengthInByte);

                    testClient.Write(
                        treeId,
                        fileId,
                        contentToWrite,
                        checker: (header, response) =>
                        {
                            status         = header.Status;
                            creditResponse = header.CreditRequestResponse;
                        });

                    if (dataLengthInByte > testClient.MaxBufferSize &&
                        config.Platform != Platform.WindowsServer2008)
                    {
                        // The server MUST validate that the length to write is within its configured maximum write size.
                        // If not, it SHOULD<283> fail the request with STATUS_INVALID_PARAMETER.
                        // <283> Section 3.3.5.13: Windows 7 and Windows Server 2008 R2 fail the request with STATUS_BUFFER_OVERFLOW instead of
                        // STATUS_INVALID_PARAMETER if the Length field is greater than Connection.MaxWriteSize.
                        // Windows Vista SP1 and Windows Server 2008 do not validate the Length field in SMB2 Write Request.
                        if (config.Platform == Platform.WindowsServer2008R2)
                        {
                            Site.Assert.AreEqual(
                                ModelSmb2Status.STATUS_BUFFER_OVERFLOW,
                                (ModelSmb2Status)status,
                                "Windows 7, Windows Server 2008 R2 fail the request with STATUS_BUFFER_OVERFLOW if exceeds max write size");
                        }
                        else
                        {
                            Site.Assert.AreNotEqual(
                                ModelSmb2Status.STATUS_SUCCESS,
                                (ModelSmb2Status)status,
                                "Server SHOULD fail the request with STATUS_INVALID_PARAMETER if exceeds max write data");
                        }
                        // Bypass the situation when data length exceeds max size that connection allows
                        CreditOperationResponse(ModelSmb2Status.STATUS_SUCCESS, creditResponse, config);
                    }
                    else
                    {
                        if (config.Platform == Platform.WindowsServer2008 &&
                            dataLengthInByte > testClient.MaxBufferSize)
                        {
                            Site.Assert.AreEqual(
                                ModelSmb2Status.STATUS_SUCCESS,
                                (ModelSmb2Status)status,
                                "Windows Vista SP1 and Windows Server 2008 do not validate the Length field in SMB2 Write Request.");

                            // Bypass the situation when data length exceeds max size that connection allows
                            CreditOperationResponse(ModelSmb2Status.STATUS_INVALID_PARAMETER, creditResponse, config);
                        }
                        else
                        {
                            CreditOperationResponse((ModelSmb2Status)status, creditResponse, config);
                        }
                    }

                    PostOperation();
                }
                catch (Exception ex)
                {
                    // Make sure testClient was set to null during disconnection correctly
                    // In case we catch a timeout exception first
                    // Temp fix for test suite bug 6349 as per discussion

                    // For an SMB2 Write request with an invalid MessageId, Windows 8 and Windows Server 2012 will stop processing
                    // the request and any further requests on that connection.
                    // So Smb2Client will throw a timeout exception instead of disconnect event.
                    // The test case should handle the timeout exception the same with disconnect event.
                    if (ex is TimeoutException || testClient.Smb2Client.IsServerDisconnected)
                    {
                        OnServerDisconnected();
                    }
                    else
                    {
                        throw;
                    }
                    return;
                }
                break;
            }

            case ModelPayloadType.ResponsePayload:
            {
                CreateFile(uncSharePath, fileName, dataLengthInByte);

                try
                {
                    string contentToRead = null;
                    testClient.Read(
                        treeId,
                        fileId,
                        0,
                        (uint)dataLengthInByte,
                        out contentToRead,
                        (header, response) =>
                        {
                            status         = header.Status;
                            creditResponse = header.CreditRequestResponse;
                        });

                    if (dataLengthInByte > testClient.MaxBufferSize)
                    {
                        // The server MUST validate that the length to read is within its configured maximum read size.
                        // If not, it SHOULD<277> fail the request with STATUS_INVALID_PARAMETER.
                        // <277> Section 3.3.5.12: Windows 7 and Windows Server 2008 R2 fail the request with STATUS_BUFFER_OVERFLOW if the Length field is greater than Connection.MaxReadSize.
                        // Windows Vista SP1 and Windows Server 2008 will fail the request with STATUS_BUFFER_OVERFLOW if the Length field is greater than 524288(0x80000).
                        if (config.Platform == Platform.WindowsServer2008 ||
                            config.Platform == Platform.WindowsServer2008R2)
                        {
                            if (config.Platform == Platform.WindowsServer2008R2)
                            {
                                Site.Assert.AreEqual(
                                    ModelSmb2Status.STATUS_BUFFER_OVERFLOW,
                                    (ModelSmb2Status)status,
                                    "Windows 7, and Windows Server 2008 R2 fail the request with STATUS_BUFFER_OVERFLOW if exceeds max read size");
                            }
                            else if (dataLengthInByte > 524288)
                            {
                                Site.Assert.AreEqual(
                                    ModelSmb2Status.STATUS_BUFFER_OVERFLOW,
                                    (ModelSmb2Status)status,
                                    "Windows Vista SP1 and Windows Server 2008 will fail the request with STATUS_BUFFER_OVERFLOW if the Length field is greater than 524288");
                            }
                        }
                        else if (config.Platform == Platform.WindowsServer2012 ||
                                 config.Platform == Platform.WindowsServer2012R2)
                        {
                            // The server MUST validate that the length to read is within its configured maximum read size.
                            // If not, it SHOULD<277> fail the request with STATUS_INVALID_PARAMETER.
                            Site.Assert.AreEqual(
                                ModelSmb2Status.STATUS_INVALID_PARAMETER,
                                (ModelSmb2Status)status,
                                "The server SHOULD fail the request with STATUS_INVALID_PARAMETER if the length is NOT within its configured maximum size.");
                        }
                        else         // NonWindows
                        {
                            Site.Assert.AreNotEqual(
                                ModelSmb2Status.STATUS_SUCCESS,
                                (ModelSmb2Status)status,
                                "Server SHOULD fail the request with STATUS_INVALID_PARAMETER if exceeds max read size");
                        }
                        // Bypass the situation when data length exceeds max size that connection allows
                        CreditOperationResponse(ModelSmb2Status.STATUS_SUCCESS, creditResponse, config);
                    }
                    else
                    {
                        CreditOperationResponse((ModelSmb2Status)status, creditResponse, config);
                    }

                    PostOperation();
                }
                catch (Exception ex)
                {
                    // Make sure testClient was set to null during disconnection correctly
                    // In case we catch a timeout exception first
                    // Temp fix for test suite bug 6349 as per discussion

                    // For an SMB2 Write request with an invalid MessageId, Windows 8 and Windows Server 2012 will stop processing
                    // the request and any further requests on that connection.
                    // So Smb2Client will throw a timeout exception instead of disconnect event.
                    // The test case should handle the timeout exception the same with disconnect event.
                    if (ex is TimeoutException || testClient.Smb2Client.IsServerDisconnected)
                    {
                        OnServerDisconnected();
                    }
                    else
                    {
                        throw;
                    }
                    return;
                }
                break;
            }

            default:
                throw new ArgumentException("payloadType");
            }

            #endregion
        }
        public void Smb2OverRdmaChannel_ReadWriteMultipleBufferDescriptorList()
        {
            InitSmbdConnectionForTestCases(smbdAdapter.TestConfig.TestFileName_LargeFile);
            uint size = smbdAdapter.Smb2MaxReadSize;

            if (size > smbdAdapter.Smb2MaxWriteSize)
            {
                size = smbdAdapter.Smb2MaxWriteSize;
            }
            int  bufferCount  = ushort.MaxValue / SmbdBufferDescriptorV1.SIZE; // SMB2 max support channel info size
            uint bufferLength = (uint)(size / bufferCount + 1);                // buffer length of each buffer descriptor

            byte[]   channelInfo  = new byte[SmbdBufferDescriptorV1.SIZE * bufferCount];
            byte[]   writeContent = Encoding.ASCII.GetBytes(Smb2Utility.CreateRandomStringInByte((int)size));
            byte[]   readContent  = new byte[size];
            NtStatus status;

            #region SMB2 Write file
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register memory and get buffer descriptor for SMB2 WRITE");
            SmbdBufferDescriptorV1[] writeDescp = new SmbdBufferDescriptorV1[bufferCount];
            for (int i = 0; i < bufferCount; ++i)
            {
                smbdAdapter.SmbdRegisterBuffer(
                    bufferLength,
                    SmbdBufferReadWrite.RDMA_READ_PERMISSION_FOR_WRITE_FILE,
                    out writeDescp[i]);
                byte[] channelInfoBlock = TypeMarshal.ToBytes <SmbdBufferDescriptorV1>(writeDescp[i]);
                Array.Copy(
                    channelInfoBlock,
                    0,
                    channelInfo,
                    SmbdBufferDescriptorV1.SIZE * i,
                    SmbdBufferDescriptorV1.SIZE);
            }
            // copy write content
            for (int index = 0, writeOffset = 0;
                 index < bufferCount && writeOffset < writeContent.Length;
                 ++index, writeOffset += (int)bufferLength)
            {
                int length = (int)bufferLength;
                if (length + writeOffset > writeContent.Length)
                {
                    length = writeContent.Length - writeOffset;
                }
                byte[] buffer = new byte[length];
                Array.Copy(writeContent, writeOffset, buffer, 0, length);
                smbdAdapter.SmbdWriteRegisteredBuffer(buffer, writeDescp[index]);
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Write content to file over RDMA.");
            WRITE_Response writeResponse;
            status = (NtStatus)smbdAdapter.Smb2WriteOverRdmaChannel(
                0,
                channelInfo,
                size,
                out writeResponse
                );
            BaseTestSite.Assert.AreEqual <NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "Status of SMB2 Write File is {0}", status);
            BaseTestSite.Assert.AreEqual <uint>(
                (uint)size,
                writeResponse.Count,
                "DataLength in WRITE response is {0}", writeResponse.Count);

            #endregion


            #region Read file from server
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register memory and get buffer descriptor for SMB2 WRITE");
            SmbdBufferDescriptorV1[] readDescp = new SmbdBufferDescriptorV1[bufferCount];
            for (int i = 0; i < bufferCount; ++i)
            {
                smbdAdapter.SmbdRegisterBuffer(
                    bufferLength,
                    SmbdBufferReadWrite.RDMA_WRITE_PERMISSION_FOR_READ_FILE,
                    out readDescp[i]);
                byte[] channelInfoBlock = TypeMarshal.ToBytes <SmbdBufferDescriptorV1>(readDescp[i]);
                Array.Copy(
                    channelInfoBlock,
                    0,
                    channelInfo,
                    SmbdBufferDescriptorV1.SIZE * i,
                    SmbdBufferDescriptorV1.SIZE);
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Read content from file over RDMA.");
            READ_Response readResponse;
            byte[]        readData;
            status = (NtStatus)smbdAdapter.Smb2ReadOverRdmaChannel(
                0,
                size,
                channelInfo,
                out readResponse,
                out readData
                );
            BaseTestSite.Assert.AreEqual <NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "Status of SMB2 Read File is {0}", status);
            BaseTestSite.Assert.AreEqual <uint>(
                0,
                readResponse.DataLength,
                "DataLength in READ response is {0}", readResponse.DataLength);
            BaseTestSite.Assert.AreEqual <int>(
                0,
                readData.Length,
                "Data length of content in response is {0}", readData.Length);
            BaseTestSite.Assert.AreEqual <byte>(
                80,
                readResponse.DataOffset,
                "DataOffset in response is {0}", readResponse.DataOffset);
            BaseTestSite.Assert.AreEqual <uint>(
                size,
                readResponse.DataRemaining,
                "DataRemaining in response is {0}", readResponse.DataRemaining);

            // read content
            for (int index = 0, readOffset = 0;
                 index < bufferCount && readOffset < readContent.Length;
                 ++index, readOffset += (int)bufferLength)
            {
                int length = (int)bufferLength;
                if (length + readOffset > readContent.Length)
                {
                    length = writeContent.Length - readOffset;
                }
                byte[] buffer = new byte[length];
                smbdAdapter.SmbdReadRegisteredBuffer(buffer, readDescp[index]);
                Array.Copy(buffer, 0, readContent, readOffset, length);
            }
            #endregion

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Check the read content is same as the one written into the file.");
            BaseTestSite.Assert.IsTrue(
                SmbdUtilities.CompareByteArray(writeContent, readContent),
                "Check content of file");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Close file.");
            smbdAdapter.Smb2CloseFile();
        }
        public void BVT_CopyOffload()
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep,
                                 "1. Create a file with specified length {0} as the source of offload copy.",
                                 TestConfig.WriteBufferLengthInKb * 1024);
            string content  = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);
            string fileName = Guid.NewGuid().ToString();
            uint   treeId;
            FILEID fileIdSrc;

            PrepareTestFile(fileName, content, out treeId, out fileIdSrc);

            BaseTestSite.Log.Add(LogEntryKind.TestStep,
                                 "2. Client sends IOCTL request with FSCTL_OFFLOAD_READ to ask server to generate the token of the content for offload copy.");
            STORAGE_OFFLOAD_TOKEN token;
            ulong fileOffsetToRead = 0;                                              //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes
            ulong copyLengthToRead = (ulong)TestConfig.WriteBufferLengthInKb * 1024; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes
            ulong transferLength;

            // Request hardware to generate a token that represents a range of file to be copied
            client.OffloadRead(
                treeId,
                fileIdSrc,
                fileOffsetToRead,
                copyLengthToRead,
                out transferLength,
                out token);

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Transfer length during OFFLOAD_READ is {0}", transferLength);
            BaseTestSite.Assert.AreEqual(copyLengthToRead, transferLength,
                                         "Transfer length {0} should be equal to copy length {1}", transferLength, copyLengthToRead);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "3. Create another file as the destination of offload copy.");
            FILEID fileIdDest;

            Smb2CreateContextResponse[] serverCreateContexts;
            client.Create(
                treeId,
                Guid.NewGuid().ToString(),
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdDest,
                out serverCreateContexts);

            // Bug 8016334
            // The destination file of CopyOffload Write should not be zero, it should be at least 512 bytes, which is the sector size.
            client.Write(treeId, fileIdDest, Smb2Utility.CreateRandomStringInByte(512));
            client.Flush(treeId, fileIdDest);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "4. Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination.");
            ulong fileOffsetToWrite = 0;              //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes
            ulong copyLengthToWrite = transferLength; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes
            ulong transferOffset    = 0;              //TransferOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes

            // Request hardware to write a range of file which is represented by the generated token
            // and length/offset to another place (a different file or different offset of the same file)
            client.OffloadWrite(
                treeId,
                fileIdDest,
                fileOffsetToWrite,
                copyLengthToWrite,
                transferOffset,
                token);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "5. Compare the content of section 1 with the content of section 2.");
            string readContent;

            // Read the content that was just offload copied
            client.Read(
                treeId,
                fileIdDest,
                fileOffsetToWrite,
                (uint)copyLengthToWrite,
                out readContent);

            BaseTestSite.Assert.IsTrue(
                readContent.Equals(content),
                "File content read should equal to original");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "6. Tear down the client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF.");
            client.Close(treeId, fileIdSrc);
            client.Close(treeId, fileIdDest);
            client.TreeDisconnect(treeId);
            client.LogOff();
        }