/// <summary>
        /// Decode MCS Send Data Indication PDU
        /// </summary>
        /// <param name="data">data to be parsed</param>
        /// <param name="domainPdu">Mcs Domain PDU</param>
        /// <returns>decoded MCS Send Data Indication PDU</returns>
        private StackPacket DecodeMcsSendDataIndicationPDU(byte[] data, DomainMCSPDU domainPdu)
        {
            // Get Send Data Indication
            SendDataIndication indication = (SendDataIndication)domainPdu.GetData();
            byte[] userData = indication.userData.ByteArrayValue;

            // Get Security Header Type
            SecurityHeaderType securityHeaderType = GetSecurityHeaderTypeByContext();

            // Peek Security Header
            bool isLicenseErrorPdu = false;
            if (clientContext.IsWaitingLicenseErrorPdu)
            {
                isLicenseErrorPdu = IsLicenseErrorSecurityHeaderExist(userData);
            }

            // Decode PDU
            if (isLicenseErrorPdu)
            {
                // License Error PDU's Basic Security Header content is alway present
                int tempIndex = 0;
                TS_SECURITY_HEADER header = ParseTsSecurityHeader(userData, ref tempIndex, SecurityHeaderType.Basic);

                // Check if PDU is encrypted
                bool isEncryptedPdu = IsFlagExist((UInt16)header.flags,
                    (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_ENCRYPT);

                // Correct Server License Error PDU's security header type if needed
                if (!isEncryptedPdu || EncryptionLevel.ENCRYPTION_LEVEL_NONE == clientContext.RdpEncryptionLevel)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }

                // Get decrypted user data
                byte[] decryptedUserData = DecryptSendDataIndication(userData, securityHeaderType);

                // Decode Server License Error PDU
                return DecodeLicenseErrorPDU(data, decryptedUserData, securityHeaderType);
            }
            else
            {
                // Get decrypted user data
                byte[] decryptedUserData = DecryptSendDataIndication(userData, securityHeaderType);

                if (clientContext.MessageChannelId == indication.channelId.Value)
                {
                    if (IsInitiateMultitransportRequestSecurityHeaderExist(userData))
                    {
                        return DecodeServerInitiateMultitransportRequest(data, decryptedUserData, securityHeaderType);
                    }
                    else if (IsHeartbeatSecurityHeaderExist(userData))
                    {
                        return DecodeServerHeartbeatPDU(data, decryptedUserData, securityHeaderType);
                    }
                    else
                    {
                        return DecodeServerAutoDetectRequestPDU(data, decryptedUserData, securityHeaderType);
                    }
                }
                // Check channel ID (IO Channel ID/Virual Channel ID)
                else if (clientContext.IOChannelId != indication.channelId.Value)
                {
                    // Decode Virtual Channel PDU
                    return DecodeVirtualChannelPDU(data, decryptedUserData, securityHeaderType);
                }
                else if (IsStandardRedirectionPdu(userData, securityHeaderType))
                {
                    return DecodeServerRedirectionPDU(data, decryptedUserData, securityHeaderType);
                }
                else
                {
                    // Decode other Send Data Indication PDUs
                    return SwitchDecodeMcsSendDataIndicationPDU(data, decryptedUserData, securityHeaderType);
                }
            }
        }
        /// <summary>
        /// Decode MCS Send Data Request PDU
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <param name="domainPdu">Mcs Domain PDU</param>
        /// <returns>decoded MCS Send Data Request PDU</returns>
        private StackPacket DecodeMcsSendDataRequestPDU(RdpbcgrServerSessionContext serverSessionContext, byte[] data, DomainMCSPDU domainPdu)
        {
            SendDataRequest indication = (SendDataRequest)domainPdu.GetData();
            byte[] userData = indication.userData.ByteArrayValue;

            bool isSecurityExchange;
            bool isClientInfo;
            bool isAutoDetectResponsePDU;
            bool isMultitransportErrorPDU;

            // Get Security Header Type
            SecurityHeaderType securityHeaderType = GetSecurityHeaderTypeByContext(serverSessionContext);

            int i = 0;
            if (userData.Length == ParseUInt16(userData, ref i, false)
                || (securityHeaderType == SecurityHeaderType.None && serverSessionContext.IOChannelId != indication.channelId.Value && serverSessionContext.McsMsgChannelId != indication.channelId.Value))
            {
                // the packet not transmitted in IO Channel cannot be Security Exchange PDU or Client Info PDU, so set all to false.
                isSecurityExchange = false;
                isClientInfo = false;
                isAutoDetectResponsePDU = false;
                isMultitransportErrorPDU = false;
            }
            else
            {
                int tempIndex = 0;
                TS_SECURITY_HEADER header = ParseTsSecurityHeader(userData, ref tempIndex, SecurityHeaderType.Basic);

                // Check if PDU is Security Exchange PDU
                isSecurityExchange = IsFlagExist((UInt16)header.flags,
                    (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_EXCHANGE_PKT);

                //Check if PDU is Client Info PDU
                isClientInfo = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_INFO_PKT);

                //check if PDU is Auto Detect Response PDU
                isAutoDetectResponsePDU = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_AUTODETECT_RSP);

                //check if PDU is Client Initiate Multitransport Error PDU
                isMultitransportErrorPDU = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_TRANSPORT_RSP);
            }

            if (isSecurityExchange)
            {
                securityHeaderType = SecurityHeaderType.Basic;
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeSecurityExchangePdu(serverSessionContext, data, decryptedUserData, securityHeaderType);
            }
            else if (isClientInfo)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientInfoPdu(data, decryptedUserData, securityHeaderType);
            }
            else if (isAutoDetectResponsePDU)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientAutoDetectResponsePDU(data, decryptedUserData, securityHeaderType);
            }
            else if (isMultitransportErrorPDU)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientInitiateMultitransportResponsePDU(data, decryptedUserData, securityHeaderType);
            }
            else
            {
                if(!serverSessionContext.IsClientToServerEncrypted)
                    securityHeaderType = SecurityHeaderType.Basic;
                // Get decrypted user data
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);

                // Check channel ID (IO Channel ID/Virual Channel ID)
                if (serverSessionContext.IOChannelId != indication.channelId.Value)
                {
                    // Decode Virtual Channel PDU
                    return DecodeVirtualChannelPDU(data, decryptedUserData, securityHeaderType);
                }

                else
                {
                    // Decode other Send Data Indication PDUs
                    return SwitchDecodeMcsSendDataRequestPDU(data, decryptedUserData, securityHeaderType);
                }
            }
        }