public void CheckNegotiateContext <T>(T request, Smb2NegotiateResponsePacket response)
        {
            if (response.PayLoad.DialectRevision != DialectRevision.Smb311)
            {
                return;
            }

            if (request is Smb2NegotiateRequestPacket)
            {
                Smb2NegotiateRequestPacket smb2Request = request as Smb2NegotiateRequestPacket;
                // 3.3.5.4: if Dialect is "3.1.1" Then the server MUST build a NegotiateContextList for its negotiate response and check Including below:
                // 1. The server MUST add an SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context to the response's NegotiateContextList.
                if (response.NegotiateContext_PREAUTH == null)
                {
                    Site.Assert.Fail("The server MUST add an SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context to the response's NegotiateContextList.");
                }

                // 2. HashAlgorithmCount MUST be set to 1
                Site.Assert.AreEqual <int>(1, response.NegotiateContext_PREAUTH.Value.HashAlgorithmCount, "The response's SMB2_PREAUTH_INTEGRITY_CAPABILITIES.HashAlgorithmCount MUST be set to 1");

                // 3. SMB2_PREAUTH_INTEGRITY_CAPABILITIES Salt buffer length same as SaltLength
                Site.Assert.AreEqual <int>(response.NegotiateContext_PREAUTH.Value.SaltLength, response.NegotiateContext_PREAUTH.Value.Salt.Length, "The response's SMB2_PREAUTH_INTEGRITY_CAPABILITIES Salt buffer length must same as SaltLength");

                // 4. If client haven't send a negotiate context the server should not response except SMB2_PREAUTH_INTEGRITY_CAPABILITIES

                if ((smb2Request.NegotiateContext_ENCRYPTION == null) && (response.NegotiateContext_ENCRYPTION != null))
                {
                    Site.Assert.Fail("The server Should not response a SMB2_ENCRYPTION_CAPABILITIES as it's not sent in request.");
                }
                if ((smb2Request.NegotiateContext_COMPRESSION == null) && (response.NegotiateContext_COMPRESSION != null))
                {
                    Site.Assert.Fail("The server Should not response a SMB2_COMPRESSION_CAPABILITIES as it's not sent in request.");
                }
                if ((smb2Request.NegotiateContext_SIGNING == null) && (response.NegotiateContext_SIGNING != null))
                {
                    Site.Assert.Fail("The server Should not response a SMB2_SIGNING_CAPABILITIES as it's not sent in request.");
                }

                if (response.NegotiateContext_ENCRYPTION != null)
                {
                    Site.Assert.AreEqual <int>(1, response.NegotiateContext_ENCRYPTION.Value.CipherCount, "The response's SMB2_ENCRYPTION_CAPABILITIES.CipherCount MUST be set to 1");
                }
            }
            else if (request is SmbNegotiateRequestPacket)
            {
                Site.Assert.IsNull(response.NegotiateContext_ENCRYPTION, "The server Should not response a SMB2_ENCRYPTION_CAPABILITIES as request is SmbNegotiateRequestPacket.");
                Site.Assert.IsNull(response.NegotiateContext_COMPRESSION, "The server Should not response a SMB2_COMPRESSION_CAPABILITIES as request is SmbNegotiateRequestPacket.");
                Site.Assert.IsNull(response.NegotiateContext_SIGNING, "The server Should not response a SMB2_SIGNING_CAPABILITIES as request is SmbNegotiateRequestPacket.");
            }
        }
        private Smb2Packet DecodeSingleResponsePacket(
            byte[] messageBytes,
            bool ignoreCompoundFlag,
            ulong realSessionId,
            uint realTreeId,
            out int consumedLength,
            out int expectedLength
            )
        {
            Packet_Header smb2Header;

            bool isLeaseBreakPacket = false;

            int offset = 0;
            smb2Header = TypeMarshal.ToStruct<Packet_Header>(messageBytes, ref offset);

            if (smb2Header.Command == Smb2Command.OPLOCK_BREAK)
            {
                ushort structureSize = TypeMarshal.ToStruct<ushort>(messageBytes, ref offset);

                if (structureSize == (ushort)OplockLeaseBreakStructureSize.LeaseBreakNotification
                    || structureSize == (ushort)OplockLeaseBreakStructureSize.LeaseBreakResponse
                    || structureSize == 9) // Add this condition temporally to handle LeaseBreakResponse is error response (i.e. structureSize == 9), but this will still hide the condition when OplockBreakResponse is error response
                {
                    isLeaseBreakPacket = true;
                }
            }

            Smb2SinglePacket packet = null;
            ushort structSize = BitConverter.ToUInt16(messageBytes, Smb2Consts.Smb2HeaderLen);

            switch (smb2Header.Command)
            {
                case Smb2Command.CANCEL:
                    packet = new Smb2CancelResponsePacket();
                    break;
                case Smb2Command.CHANGE_NOTIFY:
                    packet = new Smb2ChangeNotifyResponsePacket();
                    break;
                case Smb2Command.CLOSE:
                    packet = new Smb2CloseResponsePacket();
                    break;
                case Smb2Command.CREATE:
                    packet = new Smb2CreateResponsePacket();
                    break;
                case Smb2Command.ECHO:
                    packet = new Smb2EchoResponsePacket();
                    break;
                case Smb2Command.FLUSH:
                    packet = new Smb2FlushResponsePacket();
                    break;
                case Smb2Command.IOCTL:
                    packet = new Smb2IOCtlResponsePacket();
                    break;
                case Smb2Command.LOCK:
                    packet = new Smb2LockResponsePacket();
                    break;
                case Smb2Command.LOGOFF:
                    packet = new Smb2LogOffResponsePacket();
                    break;
                case Smb2Command.NEGOTIATE:
                    packet = new Smb2NegotiateResponsePacket();
                    break;
                case Smb2Command.OPLOCK_BREAK:
                    if (smb2Header.MessageId == ulong.MaxValue)
                    {
                        if (!isLeaseBreakPacket)
                        {
                            packet = new Smb2OpLockBreakNotificationPacket();
                        }
                        else
                        {
                            packet = new Smb2LeaseBreakNotificationPacket();
                        }
                    }
                    else
                    {
                        if (!isLeaseBreakPacket)
                        {
                            packet = new Smb2OpLockBreakResponsePacket();
                        }
                        else
                        {
                            packet = new Smb2LeaseBreakResponsePacket();
                        }
                    }
                    break;
                case Smb2Command.QUERY_DIRECTORY:
                    packet = new Smb2QueryDirectoryResponePacket();
                    break;
                case Smb2Command.QUERY_INFO:
                    packet = new Smb2QueryInfoResponsePacket();
                    break;
                case Smb2Command.READ:
                    packet = new Smb2ReadResponsePacket();
                    break;
                case Smb2Command.SESSION_SETUP:
                    packet = new Smb2SessionSetupResponsePacket();
                    break;
                case Smb2Command.SET_INFO:
                    packet = new Smb2SetInfoResponsePacket();
                    break;
                case Smb2Command.TREE_CONNECT:
                    packet = new Smb2TreeConnectResponsePacket();
                    break;
                case Smb2Command.TREE_DISCONNECT:
                    packet = new Smb2TreeDisconnectResponsePacket();
                    break;
                case Smb2Command.WRITE:
                    packet = new Smb2WriteResponsePacket();
                    break;
                default:
                    throw new InvalidOperationException("Received an unknown packet! the type of the packet is "
                        + smb2Header.Command.ToString());
            }

            if (IsErrorPacket(smb2Header))
            {
                var error = new Smb2ErrorResponsePacket();
                error.FromBytes(messageBytes, out consumedLength, out expectedLength);

                packet.Header = error.Header;
                packet.Error = error;
            }
            else
            {
                packet.FromBytes(messageBytes, out consumedLength, out expectedLength);
            }

            //if ignoreCompoundFlag is false, means the process of decoding this packet
            //is not part of the process of decoding a compound packet. We will update
            //context here.
            if (!ignoreCompoundFlag)
            {
                // TODO
            }

            return packet;
        }
        public Smb2NegotiateResponsePacket CreateNegotiateResponse(
            Smb2Endpoint endpoint,
            DialectRevision_Values dialectRevision,
            SecurityPackage securityPackage,
            ServerContextAttribute contextAttribute
            )
        {
            Smb2NegotiateResponsePacket packet = new Smb2NegotiateResponsePacket();

            SetHeader(packet, endpoint, 0);

            packet.PayLoad.SecurityMode |= NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;

            if (context.requireMessageSigning)
            {
                packet.PayLoad.SecurityMode |= NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED;
            }

            packet.PayLoad.StructureSize = NEGOTIATE_Response_StructureSize_Values.V1;
            packet.PayLoad.DialectRevision = dialectRevision;
            packet.PayLoad.ServerGuid = context.serverGuid;

            if (context.isDfsCapable)
            {
                packet.PayLoad.Capabilities |= NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DFS;
            }

            packet.PayLoad.MaxTransactSize = uint.MaxValue;
            packet.PayLoad.MaxWriteSize = uint.MaxValue;
            packet.PayLoad.MaxReadSize = uint.MaxValue;

            packet.PayLoad.SystemTime = Smb2Utility.DateTimeToFileTime(DateTime.Now);
            packet.PayLoad.ServerStartTime = Smb2Utility.DateTimeToFileTime(context.serverStartTime);

            SecurityPackageType package = SecurityPackageType.Negotiate;

            if (securityPackage == SecurityPackage.Kerberos)
            {
                package = SecurityPackageType.Kerberos;
            }
            else if (securityPackage == SecurityPackage.Nlmp)
            {
                package = SecurityPackageType.Ntlm;
            }

            AccountCredential credential = new AccountCredential(null, null, null);

            context.connectionList[endpoint.EndpointId].credential = credential;
            context.connectionList[endpoint.EndpointId].packageType = package;
            context.connectionList[endpoint.EndpointId].contextAttribute = (ServerSecurityContextAttribute)contextAttribute;

            if (package == SecurityPackageType.Negotiate)
            {
                context.connectionList[endpoint.EndpointId].gss = new SspiServerSecurityContext(
                    package,
                    credential,
                    null,
                    context.connectionList[endpoint.EndpointId].contextAttribute,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

                //Generate the first token
                context.connectionList[endpoint.EndpointId].gss.Accept(null);

                packet.PayLoad.Buffer = context.connectionList[endpoint.EndpointId].gss.Token;
                packet.PayLoad.SecurityBufferOffset = Smb2Consts.SecurityBufferOffsetInNegotiateResponse;
            }
            else
            {
                packet.PayLoad.Buffer = new byte[0];
            }
            packet.PayLoad.SecurityBufferLength = (ushort)packet.PayLoad.Buffer.Length;

            packet.Sign();

            return packet;
        }