Blame libfreerdp/core/mcs.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * T.125 Multipoint Communication Service (MCS) Protocol
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "gcc.h"
Packit 1fb8d4
Packit 1fb8d4
#include "mcs.h"
Packit 1fb8d4
#include "tpdu.h"
Packit 1fb8d4
#include "tpkt.h"
Packit 1fb8d4
#include "client.h"
Packit 1fb8d4
#include "connection.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core")
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * T.125 MCS is defined in:
Packit 1fb8d4
 *
Packit 1fb8d4
 * http://www.itu.int/rec/T-REC-T.125-199802-I/
Packit 1fb8d4
 * ITU-T T.125 Multipoint Communication Service Protocol Specification
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Connect-Initial ::= [APPLICATION 101] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	callingDomainSelector		OCTET_STRING,
Packit 1fb8d4
 * 	calledDomainSelector		OCTET_STRING,
Packit 1fb8d4
 * 	upwardFlag			BOOLEAN,
Packit 1fb8d4
 * 	targetParameters		DomainParameters,
Packit 1fb8d4
 * 	minimumParameters		DomainParameters,
Packit 1fb8d4
 * 	maximumParameters		DomainParameters,
Packit 1fb8d4
 * 	userData			OCTET_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * DomainParameters ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	maxChannelIds			INTEGER (0..MAX),
Packit 1fb8d4
 * 	maxUserIds			INTEGER (0..MAX),
Packit 1fb8d4
 * 	maxTokenIds			INTEGER (0..MAX),
Packit 1fb8d4
 * 	numPriorities			INTEGER (0..MAX),
Packit 1fb8d4
 * 	minThroughput			INTEGER (0..MAX),
Packit 1fb8d4
 * 	maxHeight			INTEGER (0..MAX),
Packit 1fb8d4
 * 	maxMCSPDUsize			INTEGER (0..MAX),
Packit 1fb8d4
 * 	protocolVersion			INTEGER (0..MAX)
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	result				Result,
Packit 1fb8d4
 * 	calledConnectId			INTEGER (0..MAX),
Packit 1fb8d4
 * 	domainParameters		DomainParameters,
Packit 1fb8d4
 * 	userData			OCTET_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Result ::= ENUMERATED
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	rt-successful			(0),
Packit 1fb8d4
 * 	rt-domain-merging		(1),
Packit 1fb8d4
 * 	rt-domain-not-hierarchical	(2),
Packit 1fb8d4
 * 	rt-no-such-channel		(3),
Packit 1fb8d4
 * 	rt-no-such-domain		(4),
Packit 1fb8d4
 * 	rt-no-such-user			(5),
Packit 1fb8d4
 * 	rt-not-admitted			(6),
Packit 1fb8d4
 * 	rt-other-user-id		(7),
Packit 1fb8d4
 * 	rt-parameters-unacceptable	(8),
Packit 1fb8d4
 * 	rt-token-not-available		(9),
Packit 1fb8d4
 * 	rt-token-not-possessed		(10),
Packit 1fb8d4
 * 	rt-too-many-channels		(11),
Packit 1fb8d4
 * 	rt-too-many-tokens		(12),
Packit 1fb8d4
 * 	rt-too-many-users		(13),
Packit 1fb8d4
 * 	rt-unspecified-failure		(14),
Packit 1fb8d4
 * 	rt-user-rejected		(15)
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * ErectDomainRequest ::= [APPLICATION 1] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	subHeight			INTEGER (0..MAX),
Packit 1fb8d4
 * 	subInterval			INTEGER (0..MAX)
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * AttachUserRequest ::= [APPPLICATION 10] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * AttachUserConfirm ::= [APPLICATION 11] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	result				Result,
Packit 1fb8d4
 * 	initiator			UserId OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * ChannelJoinRequest ::= [APPLICATION 14] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	initiator			UserId,
Packit 1fb8d4
 * 	channelId			ChannelId
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * ChannelJoinConfirm ::= [APPLICATION 15] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	result				Result,
Packit 1fb8d4
 * 	initiator			UserId,
Packit 1fb8d4
 * 	requested			ChannelId,
Packit 1fb8d4
 * 	channelId			ChannelId OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * SendDataRequest ::= [APPLICATION 25] IMPLICIT SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	initiator			UserId,
Packit 1fb8d4
 * 	channelId			ChannelId,
Packit 1fb8d4
 * 	dataPriority			DataPriority,
Packit 1fb8d4
 * 	segmentation			Segmentation,
Packit 1fb8d4
 * 	userData			OCTET_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * DataPriority ::= CHOICE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	top				NULL,
Packit 1fb8d4
 * 	high				NULL,
Packit 1fb8d4
 * 	medium				NULL,
Packit 1fb8d4
 * 	low				NULL,
Packit 1fb8d4
 * 	...
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Segmentation ::= BIT_STRING
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	begin				(0),
Packit 1fb8d4
 * 	end				(1)
Packit 1fb8d4
 * } (SIZE(2))
Packit 1fb8d4
 *
Packit 1fb8d4
 * SendDataIndication ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	initiator			UserId,
Packit 1fb8d4
 * 	channelId			ChannelId,
Packit 1fb8d4
 * 	reliability			BOOLEAN,
Packit 1fb8d4
 * 	domainReferenceID		INTEGER (0..65535) OPTIONAL,
Packit 1fb8d4
 * 	dataPriority			DataPriority,
Packit 1fb8d4
 * 	segmentation			Segmentation,
Packit 1fb8d4
 * 	userData			OCTET_STRING,
Packit 1fb8d4
 * 	totalDataSize			INTEGER OPTIONAL,
Packit 1fb8d4
 * 	nonStandard			SEQUENCE OF NonStandardParameter OPTIONAL,
Packit 1fb8d4
 * 	...
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static const BYTE callingDomainSelector[1] = "\x01";
Packit 1fb8d4
static const BYTE calledDomainSelector[1] = "\x01";
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
static const char* const mcs_result_enumerated[] =
Packit 1fb8d4
{
Packit 1fb8d4
		"rt-successful",
Packit 1fb8d4
		"rt-domain-merging",
Packit 1fb8d4
		"rt-domain-not-hierarchical",
Packit 1fb8d4
		"rt-no-such-channel",
Packit 1fb8d4
		"rt-no-such-domain",
Packit 1fb8d4
		"rt-no-such-user",
Packit 1fb8d4
		"rt-not-admitted",
Packit 1fb8d4
		"rt-other-user-id",
Packit 1fb8d4
		"rt-parameters-unacceptable",
Packit 1fb8d4
		"rt-token-not-available",
Packit 1fb8d4
		"rt-token-not-possessed",
Packit 1fb8d4
		"rt-too-many-channels",
Packit 1fb8d4
		"rt-too-many-tokens",
Packit 1fb8d4
		"rt-too-many-users",
Packit 1fb8d4
		"rt-unspecified-failure",
Packit 1fb8d4
		"rt-user-rejected"
Packit 1fb8d4
};
Packit 1fb8d4
*/
Packit 1fb8d4
Packit 1fb8d4
static int mcs_initialize_client_channels(rdpMcs* mcs, rdpSettings* settings)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !settings)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	mcs->channelCount = settings->ChannelCount;
Packit 1fb8d4
Packit 1fb8d4
	if (mcs->channelCount > mcs->channelMaxCount)
Packit 1fb8d4
		mcs->channelCount = mcs->channelMaxCount;
Packit 1fb8d4
Packit 1fb8d4
	ZeroMemory(mcs->channels, sizeof(rdpMcsChannel) * mcs->channelMaxCount);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < mcs->channelCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(mcs->channels[index].Name, settings->ChannelDefArray[index].name, 8);
Packit 1fb8d4
		mcs->channels[index].options = settings->ChannelDefArray[index].options;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a DomainMCSPDU header.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param domainMCSPDU DomainMCSPDU type
Packit 1fb8d4
 * @param length TPKT length
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 li;
Packit 1fb8d4
	BYTE choice;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!s || !domainMCSPDU || !length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpkt_read_header(s, length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpdu_read_data(s, &li))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	MCSPDU = *domainMCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_choice(s, &choice))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	*domainMCSPDU = (choice >> 2);
Packit 1fb8d4
Packit 1fb8d4
	if (*domainMCSPDU != MCSPDU)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write a DomainMCSPDU header.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param domainMCSPDU DomainMCSPDU type
Packit 1fb8d4
 * @param length TPKT length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length,
Packit 1fb8d4
                                    BYTE options)
Packit 1fb8d4
{
Packit 1fb8d4
	tpkt_write_header(s, length);
Packit 1fb8d4
	tpdu_write_data(s);
Packit 1fb8d4
	per_write_choice(s, (domainMCSPDU << 2) | options);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Initialize MCS Domain Parameters.
Packit 1fb8d4
 * @param domainParameters domain parameters
Packit 1fb8d4
 * @param maxChannelIds max channel ids
Packit 1fb8d4
 * @param maxUserIds max user ids
Packit 1fb8d4
 * @param maxTokenIds max token ids
Packit 1fb8d4
 * @param maxMCSPDUsize max MCS PDU size
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL mcs_init_domain_parameters(DomainParameters* domainParameters,
Packit 1fb8d4
                                       UINT32 maxChannelIds, UINT32 maxUserIds, UINT32 maxTokenIds, UINT32 maxMCSPDUsize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!domainParameters)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	domainParameters->maxChannelIds = maxChannelIds;
Packit 1fb8d4
	domainParameters->maxUserIds = maxUserIds;
Packit 1fb8d4
	domainParameters->maxTokenIds = maxTokenIds;
Packit 1fb8d4
	domainParameters->maxMCSPDUsize = maxMCSPDUsize;
Packit 1fb8d4
	domainParameters->numPriorities = 1;
Packit 1fb8d4
	domainParameters->minThroughput = 0;
Packit 1fb8d4
	domainParameters->maxHeight = 1;
Packit 1fb8d4
	domainParameters->protocolVersion = 2;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Domain Parameters.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param domainParameters domain parameters
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL mcs_read_domain_parameters(wStream* s, DomainParameters* domainParameters)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
Packit 1fb8d4
	if (!s || !domainParameters)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return
Packit 1fb8d4
	    ber_read_sequence_tag(s, &length) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->maxChannelIds)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->maxUserIds)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->maxTokenIds)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->numPriorities)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->minThroughput)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->maxHeight)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->maxMCSPDUsize)) &&
Packit 1fb8d4
	    ber_read_integer(s, &(domainParameters->protocolVersion));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write MCS Domain Parameters.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param domainParameters domain parameters
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL mcs_write_domain_parameters(wStream* s, DomainParameters* domainParameters)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	wStream* tmps;
Packit 1fb8d4
Packit 1fb8d4
	if (!s || !domainParameters)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	tmps = Stream_New(NULL, Stream_Capacity(s));
Packit 1fb8d4
Packit 1fb8d4
	if (!tmps)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->maxChannelIds);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->maxUserIds);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->maxTokenIds);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->numPriorities);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->minThroughput);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->maxHeight);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->maxMCSPDUsize);
Packit 1fb8d4
	ber_write_integer(tmps, domainParameters->protocolVersion);
Packit 1fb8d4
	length = Stream_GetPosition(tmps);
Packit 1fb8d4
	ber_write_sequence_tag(s, length);
Packit 1fb8d4
	Stream_Write(s, Stream_Buffer(tmps), length);
Packit 1fb8d4
	Stream_Free(tmps, TRUE);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifdef DEBUG_MCS
Packit 1fb8d4
/**
Packit 1fb8d4
 * Print MCS Domain Parameters.
Packit 1fb8d4
 * @param domainParameters domain parameters
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static void mcs_print_domain_parameters(DomainParameters* domainParameters)
Packit 1fb8d4
{
Packit 1fb8d4
	WLog_INFO(TAG,  "DomainParameters {");
Packit 1fb8d4
Packit 1fb8d4
	if (domainParameters)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_INFO(TAG,  "\tmaxChannelIds:%"PRIu32"", domainParameters->maxChannelIds);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tmaxUserIds:%"PRIu32"", domainParameters->maxUserIds);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tmaxTokenIds:%"PRIu32"", domainParameters->maxTokenIds);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tnumPriorities:%"PRIu32"", domainParameters->numPriorities);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tminThroughput:%"PRIu32"", domainParameters->minThroughput);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tmaxHeight:%"PRIu32"", domainParameters->maxHeight);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tmaxMCSPDUsize:%"PRIu32"", domainParameters->maxMCSPDUsize);
Packit 1fb8d4
		WLog_INFO(TAG,  "\tprotocolVersion:%"PRIu32"", domainParameters->protocolVersion);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_INFO(TAG,  "\tdomainParameters=%p", domainParameters);
Packit 1fb8d4
Packit 1fb8d4
	WLog_INFO(TAG,  "}");
Packit 1fb8d4
}
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Merge MCS Domain Parameters.
Packit 1fb8d4
 * @param domainParameters target parameters
Packit 1fb8d4
 * @param domainParameters minimum parameters
Packit 1fb8d4
 * @param domainParameters maximum parameters
Packit 1fb8d4
 * @param domainParameters output parameters
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_merge_domain_parameters(DomainParameters* targetParameters,
Packit 1fb8d4
                                 DomainParameters* minimumParameters,
Packit 1fb8d4
                                 DomainParameters* maximumParameters, DomainParameters* pOutParameters)
Packit 1fb8d4
{
Packit 1fb8d4
	/* maxChannelIds */
Packit 1fb8d4
	if (!targetParameters || !minimumParameters || !maximumParameters || !pOutParameters)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (targetParameters->maxChannelIds >= 4)
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->maxChannelIds = targetParameters->maxChannelIds;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (maximumParameters->maxChannelIds >= 4)
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->maxChannelIds = 4;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* maxUserIds */
Packit 1fb8d4
Packit 1fb8d4
	if (targetParameters->maxUserIds >= 3)
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->maxUserIds = targetParameters->maxUserIds;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (maximumParameters->maxUserIds >= 3)
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->maxUserIds = 3;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* maxTokenIds */
Packit 1fb8d4
	pOutParameters->maxTokenIds = targetParameters->maxTokenIds;
Packit 1fb8d4
Packit 1fb8d4
	/* numPriorities */
Packit 1fb8d4
Packit 1fb8d4
	if (minimumParameters->numPriorities <= 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->numPriorities = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* minThroughput */
Packit 1fb8d4
	pOutParameters->minThroughput = targetParameters->minThroughput;
Packit 1fb8d4
Packit 1fb8d4
	/* maxHeight */
Packit 1fb8d4
Packit 1fb8d4
	if ((targetParameters->maxHeight == 1) || (minimumParameters->maxHeight <= 1))
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->maxHeight = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* maxMCSPDUsize */
Packit 1fb8d4
Packit 1fb8d4
	if (targetParameters->maxMCSPDUsize >= 1024)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (targetParameters->maxMCSPDUsize <= 65528)
Packit 1fb8d4
		{
Packit 1fb8d4
			pOutParameters->maxMCSPDUsize = targetParameters->maxMCSPDUsize;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if ((minimumParameters->maxMCSPDUsize >= 124) && (minimumParameters->maxMCSPDUsize <= 65528))
Packit 1fb8d4
		{
Packit 1fb8d4
			pOutParameters->maxMCSPDUsize = 65528;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (maximumParameters->maxMCSPDUsize >= 124)
Packit 1fb8d4
		{
Packit 1fb8d4
			pOutParameters->maxMCSPDUsize = maximumParameters->maxMCSPDUsize;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* protocolVersion */
Packit 1fb8d4
Packit 1fb8d4
	if ((targetParameters->protocolVersion == 2) ||
Packit 1fb8d4
	    ((minimumParameters->protocolVersion <= 2) && (maximumParameters->protocolVersion >= 2)))
Packit 1fb8d4
	{
Packit 1fb8d4
		pOutParameters->protocolVersion = 2;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read an MCS Connect Initial PDU.\n
Packit 1fb8d4
 * @msdn{cc240508}
Packit 1fb8d4
 * @param mcs MCS module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 li;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BOOL upwardFlag;
Packit 1fb8d4
	UINT16 tlength;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpkt_read_header(s, &tlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpdu_read_data(s, &li))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* callingDomainSelector (OCTET_STRING) */
Packit 1fb8d4
	if (!ber_read_octet_string_tag(s, &length) || ((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(s, length);
Packit 1fb8d4
Packit 1fb8d4
	/* calledDomainSelector (OCTET_STRING) */
Packit 1fb8d4
	if (!ber_read_octet_string_tag(s, &length) || ((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(s, length);
Packit 1fb8d4
Packit 1fb8d4
	/* upwardFlag (BOOLEAN) */
Packit 1fb8d4
	if (!ber_read_BOOL(s, &upwardFlag))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* targetParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_read_domain_parameters(s, &mcs->targetParameters))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* minimumParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* maximumParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_octet_string_tag(s, &length) || ((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!gcc_read_conference_create_request(s, mcs))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_merge_domain_parameters(&mcs->targetParameters, &mcs->minimumParameters,
Packit 1fb8d4
	                                 &mcs->maximumParameters, &mcs->domainParameters))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write an MCS Connect Initial PDU.\n
Packit 1fb8d4
 * @msdn{cc240508}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param mcs MCS module
Packit 1fb8d4
 * @param user_data GCC Conference Create Request
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	wStream* tmps;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!s || !mcs || !userData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	tmps = Stream_New(NULL, Stream_Capacity(s));
Packit 1fb8d4
Packit 1fb8d4
	if (!tmps)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* callingDomainSelector (OCTET_STRING) */
Packit 1fb8d4
	ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector));
Packit 1fb8d4
	/* calledDomainSelector (OCTET_STRING) */
Packit 1fb8d4
	ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector));
Packit 1fb8d4
	/* upwardFlag (BOOLEAN) */
Packit 1fb8d4
	ber_write_BOOL(tmps, TRUE);
Packit 1fb8d4
Packit 1fb8d4
	/* targetParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_write_domain_parameters(tmps, &mcs->targetParameters))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* minimumParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_write_domain_parameters(tmps, &mcs->minimumParameters))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* maximumParameters (DomainParameters) */
Packit 1fb8d4
	if (!mcs_write_domain_parameters(tmps, &mcs->maximumParameters))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* userData (OCTET_STRING) */
Packit 1fb8d4
	ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));
Packit 1fb8d4
	length = Stream_GetPosition(tmps);
Packit 1fb8d4
	/* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */
Packit 1fb8d4
	ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);
Packit 1fb8d4
	Stream_Write(s, Stream_Buffer(tmps), length);
Packit 1fb8d4
	ret = TRUE;
Packit 1fb8d4
out:
Packit 1fb8d4
	Stream_Free(tmps, TRUE);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write an MCS Connect Response PDU.\n
Packit 1fb8d4
 * @msdn{cc240508}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param mcs MCS module
Packit 1fb8d4
 * @param user_data GCC Conference Create Response
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	wStream* tmps;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!s || !mcs || !userData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	tmps = Stream_New(NULL, Stream_Capacity(s));
Packit 1fb8d4
Packit 1fb8d4
	if (!tmps)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ber_write_enumerated(tmps, 0, MCS_Result_enum_length);
Packit 1fb8d4
	ber_write_integer(tmps, 0); /* calledConnectId */
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_write_domain_parameters(tmps, &(mcs->domainParameters)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* userData (OCTET_STRING) */
Packit 1fb8d4
	ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));
Packit 1fb8d4
	length = Stream_GetPosition(tmps);
Packit 1fb8d4
	ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
Packit 1fb8d4
	Stream_Write(s, Stream_Buffer(tmps), length);
Packit 1fb8d4
	ret = TRUE;
Packit 1fb8d4
out:
Packit 1fb8d4
	Stream_Free(tmps, TRUE);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Connect Initial.\n
Packit 1fb8d4
 * @msdn{cc240508}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_connect_initial(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	wStream* s = NULL;
Packit 1fb8d4
	size_t bm, em;
Packit 1fb8d4
	wStream* gcc_CCrq = NULL;
Packit 1fb8d4
	wStream* client_data = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	mcs_initialize_client_channels(mcs, mcs->settings);
Packit 1fb8d4
	client_data = Stream_New(NULL, 512);
Packit 1fb8d4
Packit 1fb8d4
	if (!client_data)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	gcc_write_client_data_blocks(client_data, mcs);
Packit 1fb8d4
	gcc_CCrq = Stream_New(NULL, 1024);
Packit 1fb8d4
Packit 1fb8d4
	if (!gcc_CCrq)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	gcc_write_conference_create_request(gcc_CCrq, client_data);
Packit 1fb8d4
	length = Stream_GetPosition(gcc_CCrq) + 7;
Packit 1fb8d4
	s = Stream_New(NULL, 1024 + length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	bm = Stream_GetPosition(s);
Packit 1fb8d4
	Stream_Seek(s, 7);
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_write_connect_initial(s, mcs, gcc_CCrq))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "mcs_write_connect_initial failed!");
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	em = Stream_GetPosition(s);
Packit 1fb8d4
	length = (em - bm);
Packit 1fb8d4
	Stream_SetPosition(s, bm);
Packit 1fb8d4
	tpkt_write_header(s, length);
Packit 1fb8d4
	tpdu_write_data(s);
Packit 1fb8d4
	Stream_SetPosition(s, em);
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
out:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	Stream_Free(gcc_CCrq, TRUE);
Packit 1fb8d4
	Stream_Free(client_data, TRUE);
Packit 1fb8d4
	return (status < 0 ? FALSE : TRUE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Connect Response.\n
Packit 1fb8d4
 * @msdn{cc240501}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	UINT16 tlength;
Packit 1fb8d4
	BYTE result;
Packit 1fb8d4
	UINT16 li;
Packit 1fb8d4
	UINT32 calledConnectId;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpkt_read_header(s, &tlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tpdu_read_data(s, &li))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) ||
Packit 1fb8d4
	    !ber_read_enumerated(s, &result, MCS_Result_enum_length) ||
Packit 1fb8d4
	    !ber_read_integer(s, &calledConnectId) ||
Packit 1fb8d4
	    !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||
Packit 1fb8d4
	    !ber_read_octet_string_tag(s, &length))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!gcc_read_conference_create_response(s, mcs))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG,  "gcc_read_conference_create_response failed");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Connect Response.\n
Packit 1fb8d4
 * @msdn{cc240501}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_connect_response(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	size_t bm, em;
Packit 1fb8d4
	wStream* gcc_CCrsp;
Packit 1fb8d4
	wStream* server_data;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	server_data = Stream_New(NULL, 512);
Packit 1fb8d4
Packit 1fb8d4
	if (!server_data)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!gcc_write_server_data_blocks(server_data, mcs))
Packit 1fb8d4
		goto error_data_blocks;
Packit 1fb8d4
Packit 1fb8d4
	gcc_CCrsp = Stream_New(NULL, 512 + Stream_Capacity(server_data));
Packit 1fb8d4
Packit 1fb8d4
	if (!gcc_CCrsp)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto error_data_blocks;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	gcc_write_conference_create_response(gcc_CCrsp, server_data);
Packit 1fb8d4
	length = Stream_GetPosition(gcc_CCrsp) + 7;
Packit 1fb8d4
	s = Stream_New(NULL, length + 1024);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		goto error_stream_s;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	bm = Stream_GetPosition(s);
Packit 1fb8d4
	Stream_Seek(s, 7);
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))
Packit 1fb8d4
		goto error_write_connect_response;
Packit 1fb8d4
Packit 1fb8d4
	em = Stream_GetPosition(s);
Packit 1fb8d4
	length = (em - bm);
Packit 1fb8d4
	Stream_SetPosition(s, bm);
Packit 1fb8d4
	tpkt_write_header(s, length);
Packit 1fb8d4
	tpdu_write_data(s);
Packit 1fb8d4
	Stream_SetPosition(s, em);
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	Stream_Free(gcc_CCrsp, TRUE);
Packit 1fb8d4
	Stream_Free(server_data, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
error_write_connect_response:
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
error_stream_s:
Packit 1fb8d4
	Stream_Free(gcc_CCrsp, TRUE);
Packit 1fb8d4
error_data_blocks:
Packit 1fb8d4
	Stream_Free(server_data, TRUE);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Erect Domain Request.\n
Packit 1fb8d4
 * @msdn{cc240523}
Packit 1fb8d4
 * @param mcs
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	UINT32 subHeight;
Packit 1fb8d4
	UINT32 subInterval;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	MCSPDU = DomainMCSPDU_ErectDomainRequest;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Erect Domain Request.\n
Packit 1fb8d4
 * @msdn{cc240523}
Packit 1fb8d4
 * @param mcs
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_erect_domain_request(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 12;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0);
Packit 1fb8d4
	per_write_integer(s, 0); /* subHeight (INTEGER) */
Packit 1fb8d4
	per_write_integer(s, 0); /* subInterval (INTEGER) */
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Attach User Request.\n
Packit 1fb8d4
 * @msdn{cc240524}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	MCSPDU = DomainMCSPDU_AttachUserRequest;
Packit 1fb8d4
	return mcs_read_domain_mcspdu_header(s, &MCSPDU, &length);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Attach User Request.\n
Packit 1fb8d4
 * @msdn{cc240524}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_attach_user_request(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 8;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0);
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Attach User Confirm.\n
Packit 1fb8d4
 * @msdn{cc240525}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	BYTE result;
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	MCSPDU = DomainMCSPDU_AttachUserConfirm;
Packit 1fb8d4
	status = mcs_read_domain_mcspdu_header(s, &MCSPDU, &length) &&
Packit 1fb8d4
	         per_read_enumerated(s, &result, MCS_Result_enum_length) && /* result */
Packit 1fb8d4
	         per_read_integer16(s, &(mcs->userId), MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Attach User Confirm.\n
Packit 1fb8d4
 * @msdn{cc240525}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_attach_user_confirm(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 11;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs->userId = mcs->baseChannelId++;
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2);
Packit 1fb8d4
	per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
Packit 1fb8d4
	per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Channel Join Request.\n
Packit 1fb8d4
 * @msdn{cc240526}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_channel_join_request(rdpMcs* mcs, wStream* s, UINT16* channelId)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	UINT16 userId;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s || !channelId)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	MCSPDU = DomainMCSPDU_ChannelJoinRequest;
Packit 1fb8d4
	return
Packit 1fb8d4
	    mcs_read_domain_mcspdu_header(s, &MCSPDU, &length) &&
Packit 1fb8d4
	    per_read_integer16(s, &userId, MCS_BASE_CHANNEL_ID) &&
Packit 1fb8d4
	    (userId == mcs->userId) &&
Packit 1fb8d4
	    per_read_integer16(s, channelId, 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Channel Join Request.\n
Packit 1fb8d4
 * @msdn{cc240526}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 * @param channel_id channel id
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 12;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0);
Packit 1fb8d4
	per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID);
Packit 1fb8d4
	per_write_integer16(s, channelId, 0);
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read MCS Channel Join Confirm.\n
Packit 1fb8d4
 * @msdn{cc240527}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	BYTE result;
Packit 1fb8d4
	UINT16 initiator;
Packit 1fb8d4
	UINT16 requested;
Packit 1fb8d4
	enum DomainMCSPDU MCSPDU;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s || !channelId)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	status = TRUE;
Packit 1fb8d4
	MCSPDU = DomainMCSPDU_ChannelJoinConfirm;
Packit 1fb8d4
	status &= mcs_read_domain_mcspdu_header(s, &MCSPDU, &length);
Packit 1fb8d4
	status &= per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */
Packit 1fb8d4
	status &= per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
Packit 1fb8d4
	status &= per_read_integer16(s, &requested, 0); /* requested (ChannelId) */
Packit 1fb8d4
	status &= per_read_integer16(s, channelId, 0); /* channelId */
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Channel Join Confirm.\n
Packit 1fb8d4
 * @msdn{cc240527}
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 15;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2);
Packit 1fb8d4
	per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
Packit 1fb8d4
	per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
Packit 1fb8d4
	per_write_integer16(s, channelId, 0); /* requested (ChannelId) */
Packit 1fb8d4
	per_write_integer16(s, channelId, 0); /* channelId */
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Receive MCS Disconnect Provider Ultimatum PDU.\n
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE b1, b2;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !s || !reason)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * http://msdn.microsoft.com/en-us/library/cc240872.aspx:
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
Packit 1fb8d4
	 * 21 80
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * 0x21:
Packit 1fb8d4
	 * 0 - --\
Packit 1fb8d4
	 * 0 -   |
Packit 1fb8d4
	 * 1 -   | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
Packit 1fb8d4
	 * 0 -   | of type DisconnectProviderUltimatum
Packit 1fb8d4
	 * 0 -   |
Packit 1fb8d4
	 * 0 - --/
Packit 1fb8d4
	 * 0 - --\
Packit 1fb8d4
	 * 1 -   |
Packit 1fb8d4
	 *       | DisconnectProviderUltimatum::reason = rn-user-requested (3)
Packit 1fb8d4
	 * 0x80: |
Packit 1fb8d4
	 * 1 - --/
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 * 0 - padding
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Rewind_UINT8(s);
Packit 1fb8d4
	Stream_Read_UINT8(s, b1);
Packit 1fb8d4
	Stream_Read_UINT8(s, b2);
Packit 1fb8d4
	*reason = ((b1 & 0x01) << 1) | (b2 >> 7);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send MCS Disconnect Provider Ultimatum PDU.\n
Packit 1fb8d4
 * @param mcs mcs module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT16 length = 9;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1);
Packit 1fb8d4
	per_write_enumerated(s, 0x80, 0);
Packit 1fb8d4
	status = transport_write(mcs->transport, s);
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status < 0) ? FALSE : TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL mcs_client_begin(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpContext* context;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs || !mcs->transport)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	context = mcs->transport->context;
Packit 1fb8d4
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs_send_connect_initial(mcs))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!freerdp_get_last_error(context))
Packit 1fb8d4
			freerdp_set_last_error(context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
Packit 1fb8d4
Packit 1fb8d4
		WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rdp_client_transition_to_state(context->rdp, CONNECTION_STATE_MCS_CONNECT);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Instantiate new MCS module.
Packit 1fb8d4
 * @param transport transport
Packit 1fb8d4
 * @return new MCS module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
rdpMcs* mcs_new(rdpTransport* transport)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpMcs* mcs;
Packit 1fb8d4
Packit 1fb8d4
	if (!transport)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	mcs = (rdpMcs*) calloc(1, sizeof(rdpMcs));
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	mcs->transport = transport;
Packit 1fb8d4
	mcs->settings = transport->settings;
Packit 1fb8d4
	mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);
Packit 1fb8d4
	mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);
Packit 1fb8d4
	mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);
Packit 1fb8d4
	mcs_init_domain_parameters(&mcs->domainParameters, 0, 0, 0, 0xFFFF);
Packit 1fb8d4
	mcs->channelCount = 0;
Packit 1fb8d4
	mcs->channelMaxCount = CHANNEL_MAX_COUNT;
Packit 1fb8d4
	mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;
Packit 1fb8d4
	mcs->channels = (rdpMcsChannel*) calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
Packit 1fb8d4
Packit 1fb8d4
	if (!mcs->channels)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	return mcs;
Packit 1fb8d4
out_free:
Packit 1fb8d4
	free(mcs);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free MCS module.
Packit 1fb8d4
 * @param mcs MCS module to be freed
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void mcs_free(rdpMcs* mcs)
Packit 1fb8d4
{
Packit 1fb8d4
	if (mcs)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(mcs->channels);
Packit 1fb8d4
		free(mcs);
Packit 1fb8d4
	}
Packit 1fb8d4
}