The SMB2 FILEID is used to represent an open to a file.
Пример #1
0
        /// </summary>
        /// <param name="fileId">The fileid for the directory. </param>
        /// <param name="treeId">The treeId for the directory. </param>
        /// <param name="sessionId">The sessionId for the directory. </param>
        /// <param name="searchPattern">A Unicode string containing the file name pattern to match. </param>
        /// <param name="fileInfoClass">The FileInfoClass to query. </param>
        /// <param name="returnSingleEntry">A boolean indicating whether the return single entry for query.</param>
        /// <param name="restartScan">A boolean indicating whether the enumeration should be restarted.</param>
        /// <param name="isOutBufferSizeLess">True: if OutputBufferSize is less than the size needed to return a single entry</param>
        /// of section 3.1.5.5.4</param>
        /// <returns>An NTSTATUS code that specifies the result</returns>
        public MessageStatus QueryDirectory(
            Smb2.FILEID fileId,
            uint treeId,
            ulong sessionId,
            string searchPattern         = "*",
            FileInfoClass fileinfoClass  = FileInfoClass.FILE_ID_BOTH_DIR_INFORMATION,
            bool returnSingleEntry       = false,
            bool restartScan             = false,
            bool isOutPutBufferNotEnough = false
            )
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, $"Query a directory information with fileid {fileId}");

            MessageStatus status = this.fsaAdapter.QueryDirectoryInfo(
                fileId,
                treeId,
                sessionId,
                searchPattern,
                FileInfoClass.FILE_ID_BOTH_DIR_INFORMATION,
                returnSingleEntry,
                restartScan,
                isOutPutBufferNotEnough);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, $"Query directory with search pattern {searchPattern} and return with status {status}. ");

            return(status);
        }
Пример #2
0
        /// <summary>
        /// Create directory
        /// </summary>
        /// <param name="dirName">Direcotry name</param>
        /// <param name="fileId">The fileid of the created directory</param>
        /// <param name="treeId">The treeId of the created directory</param>
        /// <param name="sessionId">The sessionId of the created directory</param>
        /// <returns>An NTSTATUS code that specifies the result</returns>
        public MessageStatus CreateDirectory(
            string dirName,
            out Smb2.FILEID fileId,
            out uint treeId,
            out ulong sessionId)
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, $"Create a directory with name: {dirName}");

            MessageStatus status = MessageStatus.SUCCESS;

            status = this.fsaAdapter.CreateFile(
                dirName,
                FileAttribute.DIRECTORY,
                CreateOptions.DIRECTORY_FILE,
                (FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE),
                (ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE),
                CreateDisposition.OPEN_IF,
                out fileId,
                out treeId,
                out sessionId
                );

            BaseTestSite.Log.Add(LogEntryKind.TestStep, $"Create directory and return with status {status}");

            return(status);
        }
        protected override void TestInitialize()
        {
            base.TestInitialize();

            testConfig = new SqosTestConfig(BaseTestSite);

            BaseTestSite.DefaultProtocolDocShortName = "MS-SQOS";

            BaseTestSite.Log.Add(LogEntryKind.Debug, "SecurityPackage for authentication: " + TestConfig.DefaultSecurityPackage);

            client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            treeId = 0;
            fileId = FILEID.Zero;

            #region Check Applicability
            TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_STORAGE_QOS_CONTROL);
            #endregion
        }
        public void CloseFile()
        {
            if (fileId.Equals(FILEID.Zero))
            {
                return;
            }

            Packet_Header header;
            TREE_DISCONNECT_Response treeDisconnectResponse;

            CheckStatusCode(
                client.TreeDisconnect(
                    1,
                    1,
                    headerFlags,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse));

            LOGOFF_Response logoffResponse;

            CheckStatusCode(
                client.LogOff(
                    1,
                    1,
                    headerFlags,
                    messageId++,
                    sessionId,
                    out header,
                    out logoffResponse));

            client.Disconnect();

            fileId = FILEID.Zero;
        }
 /// <summary>
 /// Create operation for PrepareOpen operation
 /// </summary>
 private void PrepareOpenCreate(
     Smb2FunctionalClient client,
     uint treeIdBeforeDisconnection,
     string fileName,
     out FILEID fileIdBeforDisconnection,
     out Smb2CreateContextResponse[] serverCreateContexts,
     RequestedOplockLevel_Values requestedOplocklevel,
     Smb2CreateContextRequest[] prepareContext)
 {
     client.Create(
         treeIdBeforeDisconnection,
         fileName,
         CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
         out fileIdBeforDisconnection,
         out serverCreateContexts,
         requestedOplocklevel,
         prepareContext,
         shareAccess: ShareAccess_Values.NONE,
         checker: (HASH_HEADER, response) =>
         {
         });
 }
        public override void Reset()
        {
            if (testClientBeforeDisconnection != null)
            {
                testClientBeforeDisconnection.Disconnect();
            }

            if (testClientAfterDisconnection != null)
            {
                testClientAfterDisconnection.Disconnect();
            }

            fileIdBeforDisconnection = FILEID.Zero;

            base.Reset();
        }
        /// <summary>
        /// Create an open from client, this include NEGOTIATE and SESSION_SETUP with server, TREE_CONNECT to the share and CREATE an open to file/directory
        /// </summary>
        /// <param name="client">Client used to take the operation</param>
        /// <param name="clientGuid">Client GUID for negotiation</param>
        /// <param name="targetName">File/directory name for the open</param>
        /// <param name="isDirectory">Set true if create open to a directory, set false if create open to a file</param>
        /// <param name="accessMask">Desired access when create the open</param>
        /// <param name="treeId">Out param for tree id used to connect to the share</param>
        /// <param name="fileId">Out param for file id that is associated with the open</param>
        /// <param name="shareAccess">Optional param for share access when create the open</param>
        /// <returns>Status value returned from CREATE request</returns>
        private uint CreateOpenFromClient(Smb2FunctionalClient client, Guid clientGuid, string targetName, bool isDirectory, LeaseStateValues requestLeaseState, AccessMask accessMask, out uint treeId, out FILEID fileId, ShareAccess_Values shareAccess = ShareAccess_Values.FILE_SHARE_DELETE | ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE)
        {
            #region Negotiate
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client {0} sends NEGOTIATE request with the following capabilities: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES.", clientGuid.ToString());
            client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "Negotiation is expected success, actually server returns {0}", Smb2Status.GetStatusCode(header.Status));

                    TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response);
                    TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING, response);
                });
            #endregion

            #region SESSION_SETUP
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client {0} sends SESSION_SETUP request.", clientGuid.ToString());
            status = client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            #endregion

            #region TREE_CONNECT to share
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client {0} sends TREE_CONNECT request.", clientGuid.ToString());
            status = client.TreeConnect(uncSharePath, out treeId);
            #endregion

            #region CREATE
            Smb2CreateContextResponse[] serverCreateContexts;
            CreateOptions_Values createOptions;

            if (isDirectory)
            {
                createOptions = CreateOptions_Values.FILE_DIRECTORY_FILE;
            }
            else
            {
                createOptions = CreateOptions_Values.FILE_NON_DIRECTORY_FILE;
            }

            // Include FILE_DELETE_ON_CLOSE if accessMask has DELETE
            if ((accessMask & AccessMask.DELETE) == AccessMask.DELETE)
            {
                createOptions = createOptions | CreateOptions_Values.FILE_DELETE_ON_CLOSE;
            }

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client {0} sends CREATE request with the lease state in SMB2_CREATE_REQUEST_LEASE_V2 set to {1}.", clientGuid.ToString(), requestLeaseState);
            status = client.Create(
                treeId,
                targetName,
                createOptions,
                out fileId,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                new Smb2CreateContextRequest[]
                {
                    new Smb2CreateRequestLeaseV2
                    {
                        LeaseKey = clientGuid,
                        LeaseState = requestLeaseState
                    }
                },
                accessMask: accessMask,
                shareAccess: shareAccess,
                checker: (header, response) => { });

            return status;
            #endregion
        }
        private void OpenFileAndResilientRequest(
            Smb2FunctionalClient client,
            Guid clientGuid,
            string fileName,
            uint timeoutInMilliSeconds,
            out FILEID fileId)
        {
            uint treeId;

            // connect to share
            ConnectToShare(
                client,
                clientGuid,
                out treeId);
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Connect to share '{0}' on server '{1}'", testConfig.BasicFileShare, testConfig.SutComputerName);

            // open file
            Smb2CreateContextResponse[] createContextResponse;
            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponse
            );
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Create Open with file name '{0}'", fileName);

            // resiliency request
            Packet_Header ioCtlHeader;
            IOCTL_Response ioCtlResponse;
            byte[] inputInResponse;
            byte[] outputInResponse;
            client.ResiliencyRequest(
                treeId,
                fileId,
                timeoutInMilliSeconds,
                (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request)),
                out ioCtlHeader,
                out ioCtlResponse,
                out inputInResponse,
                out outputInResponse
                );
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Resiliency request with timeout {0} milliseconds", timeoutInMilliSeconds);
        }
        public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId = 1;
                ulong sessionId = 0;
                uint treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                DialectRevision[] preferredDialects;

                logWriter.AddLog(LogLevel.Information, "Client connects to server");
                client.ConnectOverTCP(SUTIpAddress);

                if (info.CheckHigherDialect(info.smb2Info.MaxSupportedDialectRevision, DialectRevision.Smb311))
                {
                    // VALIDATE_NEGOTIATE_INFO request is only used in 3.0 and 3.0.2
                    preferredDialects = Smb2Utility.GetDialects(DialectRevision.Smb302);
                }
                else
                {
                    preferredDialects = info.requestDialect;
                }

                #region Negotiate

                DialectRevision selectedDialect;
                byte[] gssToken;
                Packet_Header header;
                clientGuid = Guid.NewGuid();
                logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
                MultiProtocolNegotiate(
                    client,
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    preferredDialects,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES | Capabilities_Values.GLOBAL_CAP_ENCRYPTION,
                    clientGuid,
                    out selectedDialect,
                    out gssToken,
                    out header,
                    out negotiateResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("NEGOTIATE", header.Status);
                    throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                #endregion

                #region Session Setup

                SESSION_SETUP_Response sessionSetupResp;

                SspiClientSecurityContext sspiClientGss =
                    new SspiClientSecurityContext(
                        SecurityPackageType,
                        Credential,
                        Smb2Utility.GetCifsServicePrincipalName(SUTName),
                        ClientSecurityContextAttribute.None,
                        SecurityTargetDataRepresentation.SecurityNativeDrep);

                // Server GSS token is used only for Negotiate authentication when enabled
                if (SecurityPackageType == SecurityPackageType.Negotiate)
                    sspiClientGss.Initialize(gssToken);
                else
                    sspiClientGss.Initialize(null);

                do
                {
                    logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                    client.SessionSetup(
                        1,
                        64,
                        Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        SESSION_SETUP_Request_Flags.NONE,
                        SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                        SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                        0,
                        sspiClientGss.Token,
                        out sessionId,
                        out gssToken,
                        out header,
                        out sessionSetupResp);

                    if ((header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || header.Status == Smb2Status.STATUS_SUCCESS) && gssToken != null && gssToken.Length > 0)
                    {
                        sspiClientGss.Initialize(gssToken);
                    }
                } while (header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SESSIONSETUP", header.Status);
                    throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                byte[] sessionKey;
                sessionKey = sspiClientGss.SessionKey;
                encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
                client.GenerateCryptoKeys(
                    sessionId,
                    sessionKey,
                    info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                    encryptionRequired,
                    null,
                    false);

                #endregion

                #region TreeConnect

                TREE_CONNECT_Response treeConnectResp;
                string uncShare = string.Format(@"\\{0}\{1}", SUTName, sharename);

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                client.TreeConnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    uncShare,
                    out treeId,
                    out header,
                    out treeConnectResp);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREECONNECT", header.Status);
                    throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                TREE_DISCONNECT_Response treeDisconnectResponse;

                #region IOCTL FSCTL_VALIDATE_NEGOTIATE_INFO

                VALIDATE_NEGOTIATE_INFO_Request validateNegotiateInfoReq;
                validateNegotiateInfoReq.Guid = clientGuid;
                validateNegotiateInfoReq.Capabilities =
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES
                    | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
                validateNegotiateInfoReq.SecurityMode = SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;
                validateNegotiateInfoReq.DialectCount = (ushort)(preferredDialects.Length);
                validateNegotiateInfoReq.Dialects = preferredDialects;
                byte[] inputBuffer = TypeMarshal.ToBytes<VALIDATE_NEGOTIATE_INFO_Request>(validateNegotiateInfoReq);
                byte[] outputBuffer;
                VALIDATE_NEGOTIATE_INFO_Response validateNegotiateInfoResp;
                IOCTL_Response ioCtlResponse;

                byte[] respInput = new byte[1024];
                FILEID ioCtlFileId = new FILEID();
                ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
                ioCtlFileId.Volatile = 0xFFFFFFFFFFFFFFFF;

                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_VALIDATE_NEGOTIATE_INFO to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO,
                    ioCtlFileId,
                    0,
                    inputBuffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out outputBuffer,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Validate Negotiate Information", header.Status);
                }
                else
                {
                    validateNegotiateInfoResp = TypeMarshal.ToStruct<VALIDATE_NEGOTIATE_INFO_Response>(outputBuffer);

                    if ((Capabilities_Values)negotiateResponse.Capabilities != validateNegotiateInfoResp.Capabilities)
                    {
                        logWriter.AddLog(LogLevel.Information, "Capabilities returned in ValidateNegotiateInfo response doesn't eaqual to server capabilities in original Negotiate response");
                    }

                    if (negotiateResponse.ServerGuid != validateNegotiateInfoResp.Guid)
                    {
                        logWriter.AddLog(LogLevel.Information, "ServerGuid returned in ValidateNegotiateInfo response doesn't eaqual to server ServerGuid in original Negotiate response");
                    }

                    if ((SecurityMode_Values)negotiateResponse.SecurityMode != validateNegotiateInfoResp.SecurityMode)
                    {
                        logWriter.AddLog(LogLevel.Information, "SecurityMode returned in ValidateNegotiateInfo response doesn't eaqual to server SecurityMode in original Negotiate response");
                    }

                    if (negotiateResponse.DialectRevision != validateNegotiateInfoResp.Dialect)
                    {
                        logWriter.AddLog(LogLevel.Information, "Validation failed for dialect supported on server");
                    }

                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_VALIDATE_NEGOTIATE_INFO is supported");
                }

                #endregion

                #region Tree Disconnect

                client.TreeDisconnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREEDISCONNECT", header.Status);
                }

                #endregion

                return result;
            }
        }
        public Smb2CreateResponsePacket CreateCreateResponseAsync(
            Smb2Endpoint endpoint,
            ulong asyncId,
            ulong messageId,
            OplockLevel_Values oplockLevel,
            CreateAction_Values createAction,
            _FILETIME creationTime,
            _FILETIME lastAccessTime,
            _FILETIME lastWriteTime,
            _FILETIME changeTime,
            ulong allocationSize,
            ulong endofFile,
            File_Attributes fileAttributes,
            FILEID fileId,
            params CREATE_CONTEXT_Values[] contexts
            )
        {
            Smb2CreateResponsePacket packet = CreateCreateResponse(endpoint, messageId, oplockLevel,
                createAction, creationTime, lastAccessTime, lastWriteTime, changeTime, allocationSize,
                endofFile, fileAttributes, fileId, contexts);

            ModifyAsyncHeader(packet, endpoint, asyncId);

            packet.Sign();

            return packet;
        }
        public Smb2CreateResponsePacket CreateCreateResponse(
            Smb2Endpoint endpoint,
            ulong messageId,
            OplockLevel_Values oplockLevel,
            CreateAction_Values createAction,
            _FILETIME creationTime,
            _FILETIME lastAccessTime,
            _FILETIME lastWriteTime,
            _FILETIME changeTime,
            ulong allocationSize,
            ulong endofFile,
            File_Attributes fileAttributes,
            FILEID fileId,
            params CREATE_CONTEXT_Values[] createContexts
            )
        {
            Smb2CreateResponsePacket packet = new Smb2CreateResponsePacket();

            SetHeader(packet, endpoint, messageId);

            packet.PayLoad.StructureSize = CREATE_Response_StructureSize_Values.V1;
            packet.PayLoad.OplockLevel = oplockLevel;
            packet.PayLoad.Reserved = 0;
            packet.PayLoad.CreateAction = createAction;
            packet.PayLoad.CreationTime = creationTime;
            packet.PayLoad.LastAccessTime = lastAccessTime;
            packet.PayLoad.LastWriteTime = lastWriteTime;
            packet.PayLoad.ChangeTime = changeTime;
            packet.PayLoad.AllocationSize = allocationSize;
            packet.PayLoad.EndofFile = endofFile;
            packet.PayLoad.FileAttributes = fileAttributes;
            packet.PayLoad.Reserved2 = 0;
            packet.PayLoad.FileId = fileId;

            if (createContexts == null)
            {
                packet.PayLoad.CreateContextsOffset = 0;
                packet.PayLoad.CreateContextsLength = 0;
                packet.PayLoad.Buffer = new byte[0];
            }
            else
            {
                packet.PayLoad.CreateContextsOffset = Smb2Consts.CreateContextOffsetInCreateResponse;

                using (MemoryStream ms = new MemoryStream())
                {
                    for (int i = 0; i < createContexts.Length; i++)
                    {
                        byte[] createContext = TypeMarshal.ToBytes(createContexts[i]);

                        if (i != (createContexts.Length - 1))
                        {
                            int alignedLen = Smb2Utility.AlignBy8Bytes(createContext.Length);

                            byte[] nextValue = BitConverter.GetBytes(alignedLen);
                            Array.Copy(nextValue, createContext, nextValue.Length);

                            ms.Write(createContext, 0, createContext.Length);

                            //write the padding 0;
                            for (int j = 0; j < (alignedLen - createContext.Length); j++)
                            {
                                ms.WriteByte(0);
                            }
                        }
                        else
                        {
                            ms.Write(createContext, 0, createContext.Length);
                        }
                    }

                    packet.PayLoad.Buffer = ms.ToArray();
                    packet.PayLoad.CreateContextsLength = (uint)packet.PayLoad.Buffer.Length;
                }
            }

            packet.Sign();

            return packet;
        }
        /// <summary>
        /// Create Smb2OpLockBreakNotificationPacket
        /// </summary>
        /// <param name="endpoint">represents where this packet will be sent</param>
        /// <param name="oplockLevel">The server MUST set this to the maximum value of the OplockLevel 
        /// that the server will accept for an acknowledgment from the client</param>
        /// <param name="fileId">An SMB2_FILEID, as specified in section 2.2.14.1</param>
        /// <returns>A Smb2OpLockBreakNotificationPacket</returns>
        public Smb2OpLockBreakNotificationPacket CreateOpLockBreakNotificationResponse(
            Smb2Endpoint endpoint,
            OPLOCK_BREAK_Notification_Packet_OplockLevel_Values oplockLevel,
            FILEID fileId
            )
        {
            Smb2OpLockBreakNotificationPacket packet = new Smb2OpLockBreakNotificationPacket();

            packet.Header.Flags = Packet_Header_Flags_Values.FLAGS_SERVER_TO_REDIR;
            packet.Header.Command = Smb2Command.OPLOCK_BREAK;
            packet.Header.MessageId = ulong.MaxValue;
            packet.Header.ProtocolId = Smb2Consts.Smb2ProtocolId;
            packet.Header.Signature = new byte[Smb2Consts.SignatureSize];
            packet.Header.StructureSize = Packet_Header_StructureSize_Values.V1;

            packet.Endpoint = endpoint;
            packet.PayLoad.FileId = fileId;
            packet.PayLoad.OplockLevel = oplockLevel;
            packet.PayLoad.Reserved = OPLOCK_BREAK_Notification_Packet_Reserved_Values.V1;
            packet.PayLoad.Reserved2 = OPLOCK_BREAK_Notification_Packet_Reserved2_Values.V1;
            packet.PayLoad.StructureSize = OPLOCK_BREAK_Notification_Packet_StructureSize_Values.V1;

            packet.Sign();

            return packet;
        }
        public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResponse, out encryptionRequired);

                #region TreeConnect

                TREE_CONNECT_Response treeConnectResp;
                string uncShare = string.Format(@"\\{0}\{1}", SUTName, sharename);

                Packet_Header header;

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
                {
                    client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
                }
                client.TreeConnect(
                    1,
                    1,
                    (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    uncShare,
                    out treeId,
                    out header,
                    out treeConnectResp);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREECONNECT", header.Status);
                    throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
                // Set it back to the configuration of the SUT.
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
                {
                    client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
                }

                #endregion

                TREE_DISCONNECT_Response treeDisconnectResponse;

                #region IOCTL FSCTL_VALIDATE_NEGOTIATE_INFO

                VALIDATE_NEGOTIATE_INFO_Request validateNegotiateInfoReq;
                validateNegotiateInfoReq.Guid = clientGuid;
                validateNegotiateInfoReq.Capabilities =
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES
                    | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
                validateNegotiateInfoReq.SecurityMode = SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;
                validateNegotiateInfoReq.DialectCount = (ushort)(info.requestDialect.Length);
                validateNegotiateInfoReq.Dialects = info.requestDialect;
                byte[] inputBuffer = TypeMarshal.ToBytes<VALIDATE_NEGOTIATE_INFO_Request>(validateNegotiateInfoReq);
                byte[] outputBuffer;
                VALIDATE_NEGOTIATE_INFO_Response validateNegotiateInfoResp;
                IOCTL_Response ioCtlResponse;

                byte[] respInput = new byte[1024];
                FILEID ioCtlFileId = new FILEID();
                ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
                ioCtlFileId.Volatile = 0xFFFFFFFFFFFFFFFF;

                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_VALIDATE_NEGOTIATE_INFO to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO,
                    ioCtlFileId,
                    0,
                    inputBuffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out outputBuffer,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Validate Negotiate Information", header.Status);
                }
                else
                {
                    validateNegotiateInfoResp = TypeMarshal.ToStruct<VALIDATE_NEGOTIATE_INFO_Response>(outputBuffer);

                    if ((Capabilities_Values)negotiateResponse.Capabilities != validateNegotiateInfoResp.Capabilities)
                    {
                        logWriter.AddLog(LogLevel.Information, "Capabilities returned in ValidateNegotiateInfo response doesn't eaqual to server capabilities in original Negotiate response");
                    }

                    if (negotiateResponse.ServerGuid != validateNegotiateInfoResp.Guid)
                    {
                        logWriter.AddLog(LogLevel.Information, "ServerGuid returned in ValidateNegotiateInfo response doesn't eaqual to server ServerGuid in original Negotiate response");
                    }

                    if ((SecurityMode_Values)negotiateResponse.SecurityMode != validateNegotiateInfoResp.SecurityMode)
                    {
                        logWriter.AddLog(LogLevel.Information, "SecurityMode returned in ValidateNegotiateInfo response doesn't eaqual to server SecurityMode in original Negotiate response");
                    }

                    if (negotiateResponse.DialectRevision != validateNegotiateInfoResp.Dialect)
                    {
                        logWriter.AddLog(LogLevel.Information, "Validation failed for dialect supported on server");
                    }

                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_VALIDATE_NEGOTIATE_INFO is supported");
                }

                #endregion

                #region Tree Disconnect

                client.TreeDisconnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREEDISCONNECT", header.Status);
                }

                #endregion

                return result;
            }
        }
        /// <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;
        }
        private void ReadFromAlternativeChannel(
            DialectRevision[] requestDialect,
            DialectRevision expectedDialect,
            IPAddress serverIp,
            IPAddress clientIp,
            uint lengthRead,
            uint treeId,
            FILEID fileId,
            out string contentRead)
        {
            contentRead = "";
            alternativeChannelClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIp, clientIp);

            #region Negotiate
            status = alternativeChannelClient.Negotiate(
                requestDialect,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status));

                    TestConfig.CheckNegotiateDialect(expectedDialect, response);
                    if (Smb2Utility.IsSmb3xFamily(expectedDialect))
                        TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response);
                });
            #endregion

            #region SESSION_SETUP
            status = alternativeChannelClient.AlternativeChannelSessionSetup(
                        mainChannelClient,
                        TestConfig.DefaultSecurityPackage,
                        TestConfig.SutComputerName,
                        TestConfig.AccountCredential,
                        TestConfig.UseServerGssToken,
                        checker: (header, response) => { });
            #endregion

            if (expectedDialect == DialectRevision.Smb2002 || expectedDialect == DialectRevision.Smb21)
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_REQUEST_NOT_ACCEPTED,
                    status,
                    "SessionSetup is expected to fail with STATUS_REQUEST_NOT_ACCEPTED.");
                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Dialect " + expectedDialect + " is not supported for multiple channel and fail as expected with STATUS_REQUEST_NOT_ACCEPTED.");
            }
            else
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    status,
                    "SessionSetup should succeed");

                #region READ
                status = alternativeChannelClient.Read(treeId, fileId, 0, lengthRead, out contentRead);
                #endregion

                #region CLOSE file
                status = alternativeChannelClient.Close(treeId, fileId);
                #endregion

                #region TREE_DISCONNECT
                status = alternativeChannelClient.TreeDisconnect(treeId);
                #endregion

                #region LOGOFF
                status = alternativeChannelClient.LogOff();
                #endregion
            }

            alternativeChannelClient.Disconnect();
        }
        /// <summary>
        /// Read content after failover
        /// </summary>
        /// <param name="server">File server name.</param>
        /// <param name="serverAccessIp">File server access IP.</param>
        /// <param name="uncSharePath">The share path to read the file.</param>
        /// <param name="file">The file name for reading content.</param>
        /// <param name="content">The content to read.</param>
        /// <param name="clientGuid">Smb2 client Guid.</param>
        /// <param name="createGuid">The Guid for smb2 create request.</param>
        /// <returns></returns>
        protected bool ReadContentAfterFailover(string server,
            IPAddress serverAccessIp,
            string uncSharePath,
            string file,
            string content,
            Guid clientGuid,
            Guid createGuid)
        {
            uint status;

            BaseTestSite.Assert.AreNotEqual(
                null,
                serverAccessIp,
                "Access IP to the file server should not be empty");
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Got IP {0} to access the file server", serverAccessIp.ToString());

            Smb2FunctionalClient afterFailover = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);
            DoUntilSucceed(() => afterFailover.ConnectToServer(TestConfig.UnderlyingTransport, server, serverAccessIp), TestConfig.FailoverTimeout,
                "Retry to connect to server until succeed within timeout span");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends NEGOTIATE request with the same clientguid of previous client.");
            status = afterFailover.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Negotiate failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends SESSION_SETUP request with the same SESSION_ID of previous client.");
            status = afterFailover.ReconnectSessionSetup(
                        beforeFailover,
                        TestConfig.DefaultSecurityPackage,
                        server,
                        TestConfig.AccountCredential,
                        TestConfig.UseServerGssToken);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "ReconnectSessionSetup failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            // Retry TreeConnect because network path may not be available immediately
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client retries TREE_CONNECT to {0} until succeed or timeout in {1} because network path may not be available immediately.", uncSharePath, TestConfig.FailoverTimeout);
            uint treeId = 0;
            status = afterFailover.TreeConnect(uncSharePath, out treeId, (header, response) => { });
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "TreeConnect failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            // Retry Create because file may not be available immediately
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client retries to send CREATE request with SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 context with PERSISTENT flag set until succeed or timeout in {0}.", TestConfig.FailoverTimeout);
            FILEID fileId = new FILEID();
            Smb2CreateContextResponse[] serverCreateContexts;
            status = DoUntilSucceed(
                () => afterFailover.Create(
                        treeId,
                        file,
                        CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        out fileId,
                        out serverCreateContexts,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        new Smb2CreateContextRequest[] {
                            new Smb2CreateDurableHandleReconnectV2
                            {
                                FileId = new FILEID { Persistent = fileId.Persistent },
                                CreateGuid = createGuid,
                                Flags = CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT
                            },
                        },
                        checker: (header, response) => { }),
                TestConfig.FailoverTimeout,
                "Retry Create until succeed within timeout span");
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Create failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            string readContent;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends READ request to read content.");
            status = afterFailover.Read(treeId, fileId, 0, (uint)content.Length, out readContent);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Read failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            BaseTestSite.Assert.IsTrue(
                content.Equals(readContent),
                "Content read after failover should be identical to that written before failover");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF");
            status = afterFailover.Close(treeId, fileId);
            status = afterFailover.TreeDisconnect(treeId);
            status = afterFailover.LogOff();
            afterFailover.Disconnect();
            return true;
        }
 private void ReadFromAlternativeChannel(
     IPAddress serverIp,
     IPAddress clientIp,
     uint lengthRead,
     uint treeId,
     FILEID fileId,
     out string contentRead)
 {
     ReadFromAlternativeChannel(
         TestConfig.RequestDialects,
         DialectRevision.Smb30,
         serverIp, clientIp, lengthRead, treeId, fileId,
         out contentRead);
 }
        /// <summary>
        /// Initialize all fields to the default values.
        /// </summary>
        private void Initialize()
        {
            Flags = testConfig.SendSignedRequest ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE;
            Dialect = DialectRevision.Smb2Unknown;
            MessageId = 0;
            GrantedCredit = 0;
            SessionKey = null;
            ServerGssToken = null;
            unchecked
            {
                TreeId = (uint)-1;
            }
            SessionId = 0;

            ParentDirectory = null;
            File = null;
            FileId = FILEID.Zero;
            IsDirectory = false;

            Locks = null;
            LockSequence = 0;
            LeaseState = LeaseStateValues.SMB2_LEASE_NONE;
            CreateContexts = null;
            OperationMessageId = 0;

            Client = new Smb2Client(Timeout);
            Client.DisableVerifySignature = this.testConfig.DisableVerifySignature;
        }
        private void WriteFromMainChannel(
            DialectRevision[] requestDialect,
            DialectRevision expectedDialect,
            IPAddress serverIp,
            IPAddress clientIp,
            string contentWrite,
            bool isNicRedundantOnServer,
            out uint treeId,
            out FILEID fileId)
        {
            mainChannelClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIp, clientIp);

            #region Negotiate
            mainChannelClient.Negotiate(
                requestDialect,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status));
                    TestConfig.CheckNegotiateDialect(expectedDialect, response);
                    if (Smb2Utility.IsSmb3xFamily(expectedDialect))
                        TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response);
                });
            #endregion

            #region SESSION_SETUP
            mainChannelClient.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            #endregion

            #region Retrieve 2nd IP on server for alternative channel if there is
            if (TestConfig.UnderlyingTransport == Smb2TransportType.Tcp
                && isNicRedundantOnServer
                && TestConfig.IsIoCtlCodeSupported(CtlCode_Values.FSCTL_QUERY_NETWORK_INTERFACE_INFO))
            {
                #region TREE_CONNECT to IPC$
                string ipcPath = Smb2Utility.GetIPCPath(TestConfig.SutComputerName);
                mainChannelClient.TreeConnect(ipcPath, out treeId);
                #endregion

                #region IOCTL FSCTL_QUERY_NETWORK_INTERFACE_INFO
                NETWORK_INTERFACE_INFO_Response[] networkInfoResponses;
                string interfaceAddress;
                bool secondAddressQueried = false;
                mainChannelClient.QueryNetworkInterfaceInfo(treeId, out networkInfoResponses);

                foreach (NETWORK_INTERFACE_INFO_Response netInfoResp in networkInfoResponses)
                {
                    interfaceAddress = netInfoResp.AddressStorage.Address;
                    if (interfaceAddress != null)
                    {
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Get NETWORK_INTERFACE_INFO: " + interfaceAddress);
                        if (interfaceAddress == serverIps[1].ToString())
                        {
                            secondAddressQueried = true;
                            BaseTestSite.Log.Add(LogEntryKind.Debug, "Address queried by IOCTL request with FSCTL_QUERY_NETWORK_INTERFACE_INFO matches server second address {0}", serverIps[1].ToString());
                            break;
                        }
                    }
                }
                BaseTestSite.Assert.IsTrue(
                    secondAddressQueried,
                    "Second address {0} should be queried by IOCTL request with FSCTL_QUERY_NETWORK_INTERFACE_INFO", serverIps[1].ToString());
                #endregion
            }
            #endregion

            #region TREE_CONNECT to share
            string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare);
            mainChannelClient.TreeConnect(uncSharePath, out treeId);
            #endregion

            #region CREATE
            Smb2CreateContextResponse[] serverCreateContexts;
            mainChannelClient.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                out fileId,
                out serverCreateContexts);
            #endregion

            if (Smb2Utility.IsSmb3xFamily(expectedDialect))
            {
                #region WRITE
                mainChannelClient.Write(treeId, fileId, contentWrite);
                #endregion
            }
        }
        private void ReconnectResilientHandle(
            Smb2FunctionalClient client,
            Guid clientGuid,
            string fileName,
            FILEID fileId,
            NtStatus expectedReconnectStatus,
            string message)
        {
            uint treeId;
            ConnectToShare(
                client,
                clientGuid,
                out treeId);
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Reconnect to resilient handle");

            Smb2CreateContextResponse[] createContextResponse;
            uint status = client.Create(
                treeId,
                fileName,
                CreateOptions_Values.NONE,
                out fileId,
                out createContextResponse,
                createContexts: new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateDurableHandleReconnect()
                        {
                            Data = fileId
                        }
                    },
                checker: (header, response) =>
                {
                    // do nothing, skip the exception
                }
                );
            BaseTestSite.Assert.AreEqual<NtStatus>(
                expectedReconnectStatus,
                (NtStatus)status,
                message);
        }
 private void WriteFromMainChannel(
     IPAddress serverIp,
     IPAddress clientIp,
     string contentWrite,
     bool isNicRedundantOnServer,
     out uint treeId,
     out FILEID fileId)
 {
     WriteFromMainChannel(
         TestConfig.RequestDialects,
         DialectRevision.Smb30,
         serverIp, clientIp, contentWrite, isNicRedundantOnServer,
         out treeId, out fileId);
 }
        /// <summary>
        /// Reset all member variables before running next test case
        /// </summary>
        public override void Reset()
        {
            if (firstClient != null)
            {
                firstClient.Disconnect();
                firstClient = null;
            }

            if (secondClient != null)
            {
                secondClient.Disconnect();
                secondClient = null;
            }

            fileName = null;
            leaseBreakState = LeaseBreakState.NoLeaseBreak;
            treeId1 = 0;
            treeId2 = 0;
            fileId1 = FILEID.Zero;
            fileId2 = FILEID.Zero;
            base.Reset();
        }
        private void PrepareFileForTrimming(out uint treeId, out FILEID fileId)
        {
            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb30);
            TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_FILE_LEVEL_TRIM);
            #endregion

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

            status = client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                            Smb2Status.STATUS_SUCCESS,
                            header.Status,
                            "CREATE should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status));

                    TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response);
                });

            status = client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);

            status = client.TreeConnect(uncSharePath, out treeId);

            Smb2CreateContextResponse[] serverCreateContexts;
            status = client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts);

            status = client.Write(treeId, fileId, contentWrite);

            status = client.Close(treeId, fileId);

            status = client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts);
        }
 /// <summary>
 /// Create operation for Open operation
 /// </summary>
 private uint OpenCreate(
     Smb2FunctionalClient client,
     uint treeIdAfterDisconnection,
     string fileName,
     out FILEID fileIdAfterDisconnection,
     out Smb2CreateContextResponse[] serverCreateContexts,
     RequestedOplockLevel_Values requestedOplocklevel,
     Smb2CreateContextRequest[] openContext)
 {
     return client.Create(
         treeIdAfterDisconnection,
         fileName,
         CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
         out fileIdAfterDisconnection,
         out serverCreateContexts,
         requestedOplocklevel,
         openContext,
         shareAccess: ShareAccess_Values.NONE,
         checker: (header, response) =>
         {
         });
 }
        protected override void TestInitialize()
        {
            base.TestInitialize();

            smb2client = null;

            //The SMB2 server MUST reserve -1 for invalid FileId
            fileId = FILEID.Invalid;

            // The SMB2 server MUST reserve -1 for invalid TreeId.
            treeId = 0xFFFF;
        }
        private void ClientTearDown(Smb2FunctionalClient client, uint treeId, FILEID fileId)
        {
            status = client.Close(treeId, fileId);

            status = client.TreeDisconnect(treeId);

            status = client.LogOff();
        }
        private void OpenFile(
            Smb2FunctionalClient client,
            Guid clientGuid,
            string fileName,
            bool isPersistentHandle,
            out Guid createGuid,
            out uint treeId,
            out FILEID fileId)
        {
            // connect to share
            ConnectToShare(
                client,
                clientGuid,
                out treeId);
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Connect to share '{0}' on scaleout server '{1}'", testConfig.BasicFileShare, testConfig.SutComputerName);

            #region Construct Create Context
            List<Smb2CreateContextRequest> createContextList = new List<Smb2CreateContextRequest>();
            createGuid = Guid.Empty;
            if (isPersistentHandle)
            {
                // durable handle request context
                createGuid = Guid.NewGuid();
                createContextList.Add(new Smb2CreateDurableHandleRequestV2()
                        {
                            CreateGuid = createGuid,
                            Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT,
                            Timeout = 0 // default
                        });
            }
            #endregion

            // open file
            Smb2CreateContextResponse[] createContextResponses;
            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponses,
                createContexts: createContextList.ToArray<Smb2CreateContextRequest>()
            );
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Create Open with file name '{0}'", fileName);

            #region check whether Persistent Handle is created successfully with current status
            if (isPersistentHandle)
            {
                BaseTestSite.Assert.IsTrue(
                    CheckDurableCreateContextResponse(createContextResponses),
                    "Create Response should contain Smb2CreateDurableHandleResponseV2.");
            }
            #endregion
        }
        /// <summary>
        /// Disconnect from server.
        /// Including 3 steps: 1. TreeDisconnect 2. Logoff 3. Tcp disconnection in order.
        /// </summary>
        /// <param name="timeout">The pending time to get server's response in step 1 or 2</param>
        /// <exception cref="System.Net.ProtocolViolationException">Fail to disconnect from server</exception>
        /// <exception cref="System.InvalidOperationException">The transport is not connected</exception>
        public override void Disconnect(TimeSpan timeout)
        {
            if (this.client == null)
            {
                throw new InvalidOperationException("The transport is not connected.");
            }
            uint status;

            // Tree disconnect:
            Packet_Header header;
            TREE_DISCONNECT_Response treeDisconnectResponse;

            status = client.TreeDisconnect(
                1,
                1,
                headerFlags,
                messageId++,
                sessionId,
                treeId,
                out header,
                out treeDisconnectResponse);

            if (status != 0)
            {
                throw new ProtocolViolationException("Tree Disconnect Failed. ErrorCode: " + status);
            }

            // Log off:
            LOGOFF_Response logoffResponse;

            status = client.LogOff(
                1,
                1,
                headerFlags,
                messageId++,
                sessionId,
                out header,
                out logoffResponse);

            if (status != 0)
            {
                throw new ProtocolViolationException("Log off Failed. ErrorCode: " + status);
            }

            this.client.Disconnect();

            fileId = FILEID.Zero;
        }
        private void PrepareTestFile(string fileName, string content, out uint treeId, out FILEID fileId)
        {
            client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
            client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "NEGOTIATE should succeed.");

                    TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response);
                });

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

            string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare);
            client.TreeConnect(uncSharePath, out treeId);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file.");
            Smb2CreateContextResponse[] serverCreateContexts;
            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts);

            client.Write(treeId, fileId, content);

            // Flush written content to backend storage to avoid cache.
            client.Flush(treeId, fileId);
        }
        private void SendCreateRequestWithSpecificAppInstanceversion(
            Smb2FunctionalClient client,
            Guid appInstanceId,
            ulong? appInstanceVersionHigh,
            ulong? appInstanceVersionLow,
            DialectRevision dialect,
            uint expectedCreateResponseStatus,
            out uint treeId,
            out FILEID fileId
            )
        {
            #region Client connects to Server
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client connects to the file server by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
            client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic1IPAddress);
            client.Negotiate(Smb2Utility.GetDialects(dialect), TestConfig.IsSMB1NegotiateEnabled);
            client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);

            client.TreeConnect(uncSharePath, out treeId);

            Smb2CreateContextResponse[] serverCreateContexts;
            Smb2CreateAppInstanceVersion appInstanceVersion = new Smb2CreateAppInstanceVersion();
            Smb2CreateContextRequest[] clientCreateContexts;

            if (appInstanceVersionHigh.HasValue && appInstanceVersionLow.HasValue)
            {
                appInstanceVersion.AppInstanceVersionHigh = appInstanceVersionHigh.Value;
                appInstanceVersion.AppInstanceVersionLow = appInstanceVersionLow.Value;
                clientCreateContexts =
                new Smb2CreateContextRequest[] {
                    new Smb2CreateAppInstanceId
                    {
                        AppInstanceId = appInstanceId
                    },
                    appInstanceVersion
                };
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request with AppInstanceVersionHigh = {0}, AppInstanceVersionLow = {1}.", appInstanceVersion.AppInstanceVersionHigh, appInstanceVersion.AppInstanceVersionLow);
            }
            else
            {
                clientCreateContexts =
                new Smb2CreateContextRequest[] {
                    new Smb2CreateAppInstanceId
                    {
                        AppInstanceId = appInstanceId
                    }
                };
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request without AppInstanceVersion.");
            }

            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                clientCreateContexts,
                shareAccess: ShareAccess_Values.NONE,
                checker: (header, response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        expectedCreateResponseStatus,
                        header.Status,
                        (expectedCreateResponseStatus == Smb2Status.STATUS_SUCCESS ?
                        "The open will be closed. Create should succeed. Actually server returns with {0}."
                        : "The open cannot be closed. Create should not succeed. Actually server returns with {0}."),
                        Smb2Status.GetStatusCode(header.Status));
                });

            #endregion
        }
        /// <summary>
        /// Read from alternative channel over RDMA
        /// </summary>
        /// <param name="content">File content to be compared.</param>
        /// <param name="lengthRead">Data length to be read.</param>
        /// <param name="treeId">Tree Connect Id.</param>
        /// <param name="fileId">File Id.</param>
        private void ReadFromAlternativeChannel(
            byte[] content,
            uint lengthRead,
            uint treeId,
            FILEID fileId
            )
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Read from alternative channel over RDMA.");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "ServerRNicIp: " + testConfig.ServerRNicIp);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "ClientRNicIp: " + testConfig.ClientRNicIp);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Data length to be read: " + lengthRead.ToString());

            NtStatus status;
            #region Query Network information
            NETWORK_INTERFACE_INFO_Response[] networkInterfaceInfos;
            status = (NtStatus)mainChannelClient.Smb2QueryNetworkInterfaceInfo(out networkInterfaceInfos);

            BaseTestSite.Assert.AreEqual<NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "Status of Query Network Interface Info is {0}", status);
            bool containRdmaNicIPAddress = false;
            foreach (NETWORK_INTERFACE_INFO_Response networkInterfaceInfo in networkInterfaceInfos)
            {
                NETWORK_INTERFACE_INFO_Response_Capabilities capability = networkInterfaceInfo.Capability;
                capability |= NETWORK_INTERFACE_INFO_Response_Capabilities.RDMA_CAPABLE;
                if (capability == networkInterfaceInfo.Capability
                    && testConfig.ServerRNicIp.Equals(networkInterfaceInfo.AddressStorage.Address))
                {
                    containRdmaNicIPAddress = true;
                    break;
                }
            }
            if (!containRdmaNicIPAddress)
            {
                BaseTestSite.Assert.Fail("No RDMA capable network can be found.");
            }
            #endregion

            IPAddress clientIp = IPAddress.Parse(testConfig.ClientRNicIp);
            status = alternativeChannelClient.ConnectToServerOverRDMA(
                testConfig.ClientRNicIp,
                testConfig.ServerRNicIp,
                testConfig.SmbdTcpPort,
                clientIp.AddressFamily,
                testConfig.InboundEntries,
                testConfig.OutboundEntries,
                testConfig.InboundReadLimit,
                testConfig.MaxReceiveSize);

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

            // SMBD negotiate
            SmbdNegotiateResponse response;
            status = alternativeChannelClient.SmbdNegotiate(
                SmbdVersion.V1,
                SmbdVersion.V1,
                0,
                (ushort)testConfig.SendCreditTarget,
                (ushort)testConfig.ReceiveCreditMax,
                (uint)testConfig.MaxSendSize,
                (uint)testConfig.MaxReceiveSize,
                (uint)testConfig.MaxFragmentedSize,
                out response
                );
            BaseTestSite.Assert.AreEqual<NtStatus>(
                NtStatus.STATUS_SUCCESS,
                status,
                "Status of SmbdNegotiate is {0}", status);

            // SMB2 Negotiate
            DialectRevision[] negotiatedDialects = new DialectRevision[] { DialectRevision.Smb30, DialectRevision.Smb2002, DialectRevision.Smb21 };
            DialectRevision selectedDialect;
            status = (NtStatus)alternativeChannelClient.Smb2Negotiate(negotiatedDialects, out selectedDialect);
            BaseTestSite.Assert.AreEqual<NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Negotiate is {0}", status);

            // SMB2 Session Setup
            status = (NtStatus)alternativeChannelClient.Smb2AlternativeChannelSessionSetup(
                mainChannelClient,
                testConfig.DomainName,
                testConfig.UserName,
                testConfig.Password,
                testConfig.ServerName
                );
            BaseTestSite.Assert.AreEqual<NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Session Setup is {0}", status);
            // Set treeId and fileId
            alternativeChannelClient.TreeId = treeId;
            alternativeChannelClient.FileId = fileId;

            // Send each read request according to SMB2 read file limit
            uint maxReadSize = alternativeChannelClient.Smb2MaxReadSize;
            uint offset = 0;
            while (offset < lengthRead)
            {
                uint length = maxReadSize;
                if (offset + length > lengthRead)
                {
                    length = lengthRead - offset;
                }

                // Register Memory for RDMA read
                byte[] directMemory = new byte[length];
                SmbdBufferDescriptorV1 descp;
                alternativeChannelClient.SmbdRegisterBuffer(
                    length,
                    SmbdBufferReadWrite.RDMA_READ_WRITE_PERMISSION_FOR_WRITE_READ_FILE,
                    testConfig.ReversedBufferDescriptor,
                    out descp);
                byte[] channelInfo = TypeMarshal.ToBytes<SmbdBufferDescriptorV1>(descp);

                // Read over RDMA channel
                READ_Response readResponse;
                byte[] readData;
                status = (NtStatus)alternativeChannelClient.Smb2ReadOverRdmaChannel(
                    (UInt64)offset,
                    (uint)length,
                    channelInfo,
                    out readResponse,
                    out readData
                    );

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

                alternativeChannelClient.SmbdReadRegisteredBuffer(directMemory, descp);
                BaseTestSite.Assert.IsTrue(SmbdUtilities.CompareByteArray(directMemory, content), "Check file content");

                offset += length;
            }

            status = (NtStatus)alternativeChannelClient.Smb2CloseFile();
            BaseTestSite.Assert.AreEqual<NtStatus>(NtStatus.STATUS_SUCCESS, status, "Status of SMB2 Close file is {0}", status);

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

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