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;
        }
 /// <summary>
 /// Handle re-authenticate event
 /// </summary>
 /// <param name="packet">The session setup response packet</param>
 /// <param name="connectionId">Used to find the connection</param>
 private void HandleReAuthenticateEvent(Smb2SessionSetupResponsePacket packet, int connectionId)
 {
     if (packet.Header.Status == 0)
     {
         globalSessionTable[packet.GetSessionId()].state = SessionState.Valid;
     }
 }
        public Smb2SessionSetupResponsePacket CreateSessionSetupResponse(
            Smb2Endpoint endpoint,
            ulong messageId,
            ulong sessionId,
            SessionFlags_Values sessionFlags
            )
        {
            //This is for re-authenticate. the state is used to indicate user that
            //the authenticate process in not complete.
            if (context.globalSessionTable.ContainsKey(sessionId))
            {
                context.globalSessionTable[sessionId].state = SessionState.InProgress;
            }

            Smb2SessionSetupResponsePacket packet = new Smb2SessionSetupResponsePacket();

            SetHeader(packet, 0, endpoint, messageId);

            packet.Header.SessionId = sessionId;
            packet.PayLoad.StructureSize = SESSION_SETUP_Response_StructureSize_Values.V1;
            packet.PayLoad.SessionFlags = sessionFlags;

            Smb2SessionSetupRequestPacket requestPacket = context.FindRequestPacket(endpoint.EndpointId, messageId)
                as Smb2SessionSetupRequestPacket;

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

                context.connectionList[endpoint.EndpointId].gss.Accept(requestPacket.PayLoad.Buffer);
            }
            else
            {
                context.connectionList[endpoint.EndpointId].gss.Accept(requestPacket.PayLoad.Buffer);
            }

            if (context.connectionList[endpoint.EndpointId].gss.NeedContinueProcessing)
            {
                packet.Header.Status = (uint)Smb2Status.STATUS_MORE_PROCESSING_REQUIRED;
            }

            packet.PayLoad.Buffer = context.connectionList[endpoint.EndpointId].gss.Token;

            packet.PayLoad.SecurityBufferOffset = Smb2Consts.SecurityBufferOffsetInSessionSetup;
            packet.PayLoad.SecurityBufferLength = (ushort)packet.PayLoad.Buffer.Length;

            packet.Sign();

            return packet;
        }
        /// <summary>
        /// Handle the event of authenticate
        /// </summary>
        /// <param name="packet">The session setup response packet</param>
        /// <param name="connectionId">Used to find the connection</param>
        private void HandleNewAuthenticateEvent(Smb2SessionSetupResponsePacket packet, int connectionId)
        {
            if (!globalSessionTable.ContainsKey(packet.GetSessionId()))
            {
                Smb2ServerSession session = new Smb2ServerSession();

                session.connection = connectionList[connectionId];
                session.state = SessionState.InProgress;
                session.securityContext = null;
                session.sessionId = packet.GetSessionId();
                session.openTable = new Dictionary<FILEID, Smb2ServerOpen>();
                session.treeConnectTable = new Dictionary<uint, Smb2ServerTreeConnect>();

                globalSessionTable.Add(session.sessionId, session);
            }

            Smb2SessionSetupRequestPacket requestPacket = FindRequestPacket(connectionId, packet.Header.MessageId)
                as Smb2SessionSetupRequestPacket;

            if (packet.Header.Status == 0)
            {
                if (connectionList[connectionId].clientCapabilities == 0)
                {
                    connectionList[connectionId].clientCapabilities = requestPacket.PayLoad.Capabilities;
                }

                if (((packet.PayLoad.SessionFlags & SessionFlags_Values.SESSION_FLAG_IS_GUEST) == SessionFlags_Values.SESSION_FLAG_IS_GUEST)
                    || ((packet.PayLoad.SessionFlags & SessionFlags_Values.SESSION_FLAG_IS_NULL) == SessionFlags_Values.SESSION_FLAG_IS_NULL))
                {
                    //should sign set to false. do not need to set it manually.
                }
                else
                {
                    if (((requestPacket.PayLoad.SecurityMode & SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED)
                        == SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED) && (this.requireMessageSigning ||
                        connectionList[connectionId].shouldSign))
                    {
                        globalSessionTable[packet.GetSessionId()].shouldSign = true;
                    }
                }

                globalSessionTable[packet.GetSessionId()].sessionKey = connectionList[connectionId].gss.SessionKey;
                globalSessionTable[packet.GetSessionId()].state = SessionState.Valid;
                //Set it to null because if another authentiate request arrives, gss must be
                //set to a new one. set to null as a flag to indicate gss must re-construct.

                //release gss, set to null
                connectionList[connectionId].ReleaseSspiServer();
            }
        }