Blame libfreerdp/core/gateway/rts.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Request To Send (RTS) PDUs
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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 <winpr/crypto.h>
Packit 1fb8d4
#include <winpr/winhttp.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "ncacn_http.h"
Packit 1fb8d4
#include "rpc_client.h"
Packit 1fb8d4
Packit 1fb8d4
#include "rts.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core.gateway.rts")
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * RTS PDU Header
Packit 1fb8d4
 *
Packit 1fb8d4
 * The RTS PDU Header has the same layout as the common header of the connection-oriented RPC
Packit 1fb8d4
 * PDU as specified in [C706] section 12.6.1, with a few additional requirements around the contents
Packit 1fb8d4
 * of the header fields. The additional requirements are as follows:
Packit 1fb8d4
 *
Packit 1fb8d4
 * All fields MUST use little-endian byte order.
Packit 1fb8d4
 *
Packit 1fb8d4
 * Fragmentation MUST NOT occur for an RTS PDU.
Packit 1fb8d4
 *
Packit 1fb8d4
 * PFC_FIRST_FRAG and PFC_LAST_FRAG MUST be present in all RTS PDUs, and all other PFC flags
Packit 1fb8d4
 * MUST NOT be present.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The rpc_vers and rpc_vers_minor fields MUST contain version information as described in
Packit 1fb8d4
 * [MS-RPCE] section 1.7.
Packit 1fb8d4
 *
Packit Service 5a9772
 * PTYPE MUST be set to a value of 20 (0x14). This field differentiates RTS packets from other RPC
Packit Service 5a9772
 * packets.
Packit 1fb8d4
 *
Packit Service 5a9772
 * The packed_drep MUST indicate little-endian integer and floating-pointer byte order, IEEE
Packit Service 5a9772
 * float-point format representation, and ASCII character format as specified in [C706]
Packit Service 5a9772
 * section 12.6.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The auth_length MUST be set to 0.
Packit 1fb8d4
 *
Packit Service 5a9772
 * The frag_length field MUST reflect the size of the header plus the size of all commands,
Packit Service 5a9772
 * including the variable portion of variable-sized commands.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The call_id MUST be set to 0 by senders and MUST be 0 on receipt.
Packit 1fb8d4
 *
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static void rts_pdu_header_init(rpcconn_rts_hdr_t* header)
Packit 1fb8d4
{
Packit 1fb8d4
	ZeroMemory(header, sizeof(*header));
Packit 1fb8d4
	header->rpc_vers = 5;
Packit 1fb8d4
	header->rpc_vers_minor = 0;
Packit 1fb8d4
	header->ptype = PTYPE_RTS;
Packit 1fb8d4
	header->packed_drep[0] = 0x10;
Packit 1fb8d4
	header->packed_drep[1] = 0x00;
Packit 1fb8d4
	header->packed_drep[2] = 0x00;
Packit 1fb8d4
	header->packed_drep[3] = 0x00;
Packit 1fb8d4
	header->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
Packit 1fb8d4
	header->auth_length = 0;
Packit 1fb8d4
	header->call_id = 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_receive_window_size_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length,
Packit Service 5a9772
                                                UINT32* ReceiveWindowSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (ReceiveWindowSize)
Packit Service 5a9772
		*ReceiveWindowSize = *((UINT32*)&buffer[0]); /* ReceiveWindowSize (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_receive_window_size_command_write(BYTE* buffer, UINT32 ReceiveWindowSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_RECEIVE_WINDOW_SIZE; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = ReceiveWindowSize;           /* ReceiveWindowSize (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_flow_control_ack_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length,
Packit Service 5a9772
                                             UINT32* BytesReceived, UINT32* AvailableWindow,
Packit Service 5a9772
                                             BYTE* ChannelCookie)
Packit 1fb8d4
{
Packit 1fb8d4
	/* Ack (24 bytes) */
Packit 1fb8d4
	if (BytesReceived)
Packit Service 5a9772
		*BytesReceived = *((UINT32*)&buffer[0]); /* BytesReceived (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (AvailableWindow)
Packit Service 5a9772
		*AvailableWindow = *((UINT32*)&buffer[4]); /* AvailableWindow (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (ChannelCookie)
Packit 1fb8d4
		CopyMemory(ChannelCookie, &buffer[8], 16); /* ChannelCookie (16 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	return 24;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_flow_control_ack_command_write(BYTE* buffer, UINT32 BytesReceived,
Packit Service 5a9772
                                              UINT32 AvailableWindow, BYTE* ChannelCookie)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_FLOW_CONTROL_ACK; /* CommandType (4 bytes) */
Packit 1fb8d4
		/* Ack (24 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = BytesReceived;     /* BytesReceived (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[8]) = AvailableWindow;   /* AvailableWindow (4 bytes) */
Packit 1fb8d4
		CopyMemory(&buffer[12], ChannelCookie, 16); /* ChannelCookie (16 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 28;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_connection_timeout_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length,
Packit Service 5a9772
                                               UINT32* ConnectionTimeout)
Packit 1fb8d4
{
Packit 1fb8d4
	if (ConnectionTimeout)
Packit Service 5a9772
		*ConnectionTimeout = *((UINT32*)&buffer[0]); /* ConnectionTimeout (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_connection_timeout_command_write(BYTE* buffer, UINT32 ConnectionTimeout)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_CONNECTION_TIMEOUT; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = ConnectionTimeout;          /* ConnectionTimeout (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_cookie_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* Cookie (16 bytes) */
Packit 1fb8d4
	return 16;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_cookie_command_write(BYTE* buffer, BYTE* Cookie)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_COOKIE; /* CommandType (4 bytes) */
Packit Service 5a9772
		CopyMemory(&buffer[4], Cookie, 16);      /* Cookie (16 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 20;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_channel_lifetime_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* ChannelLifetime (4 bytes) */
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_channel_lifetime_command_write(BYTE* buffer, UINT32 ChannelLifetime)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_CHANNEL_LIFETIME; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = ChannelLifetime;          /* ChannelLifetime (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_client_keepalive_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* ClientKeepalive (4 bytes) */
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_client_keepalive_command_write(BYTE* buffer, UINT32 ClientKeepalive)
Packit 1fb8d4
{
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * An unsigned integer that specifies the keep-alive interval, in milliseconds,
Packit 1fb8d4
	 * that this connection is configured to use. This value MUST be 0 or in the inclusive
Packit 1fb8d4
	 * range of 60,000 through 4,294,967,295. If it is 0, it MUST be interpreted as 300,000.
Packit 1fb8d4
	 */
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_CLIENT_KEEPALIVE; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = ClientKeepalive;          /* ClientKeepalive (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_version_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* Version (4 bytes) */
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_version_command_write(BYTE* buffer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_VERSION; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = 1;               /* Version (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_empty_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_empty_command_write(BYTE* buffer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_EMPTY; /* CommandType (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static SSIZE_T rts_padding_command_read(const BYTE* buffer, size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 ConformanceCount;
Packit Service 5a9772
	ConformanceCount = *((UINT32*)&buffer[0]); /* ConformanceCount (4 bytes) */
Packit 1fb8d4
	/* Padding (variable) */
Packit 1fb8d4
	return ConformanceCount + 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_padding_command_write(BYTE* buffer, UINT32 ConformanceCount)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_PADDING;  /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = ConformanceCount; /* ConformanceCount (4 bytes) */
Packit Service 5a9772
		ZeroMemory(&buffer[8], ConformanceCount);  /* Padding (variable) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8 + ConformanceCount;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_negative_ance_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_negative_ance_command_write(BYTE* buffer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_NEGATIVE_ANCE; /* CommandType (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_ance_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_ance_command_write(BYTE* buffer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_ANCE; /* CommandType (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static SSIZE_T rts_client_address_command_read(const BYTE* buffer, size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 AddressType;
Packit Service 5a9772
	AddressType = *((UINT32*)&buffer[0]); /* AddressType (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (AddressType == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* ClientAddress (4 bytes) */
Packit 1fb8d4
		/* padding (12 bytes) */
Packit 1fb8d4
		return 4 + 4 + 12;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		/* ClientAddress (16 bytes) */
Packit 1fb8d4
		/* padding (12 bytes) */
Packit 1fb8d4
		return 4 + 16 + 12;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_client_address_command_write(BYTE* buffer, UINT32 AddressType, BYTE* ClientAddress)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_CLIENT_ADDRESS; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = AddressType;            /* AddressType (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (AddressType == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (buffer)
Packit 1fb8d4
		{
Packit 1fb8d4
			CopyMemory(&buffer[8], ClientAddress, 4); /* ClientAddress (4 bytes) */
Packit Service 5a9772
			ZeroMemory(&buffer[12], 12);              /* padding (12 bytes) */
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		return 24;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (buffer)
Packit 1fb8d4
		{
Packit 1fb8d4
			CopyMemory(&buffer[8], ClientAddress, 16); /* ClientAddress (16 bytes) */
Packit Service 5a9772
			ZeroMemory(&buffer[24], 12);               /* padding (12 bytes) */
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		return 36;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_association_group_id_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* AssociationGroupId (16 bytes) */
Packit 1fb8d4
	return 16;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_association_group_id_command_write(BYTE* buffer, BYTE* AssociationGroupId)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_ASSOCIATION_GROUP_ID; /* CommandType (4 bytes) */
Packit Service 5a9772
		CopyMemory(&buffer[4], AssociationGroupId, 16);        /* AssociationGroupId (16 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 20;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_destination_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length,
Packit 1fb8d4
                                        UINT32* Destination)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Destination)
Packit Service 5a9772
		*Destination = *((UINT32*)&buffer[0]); /* Destination (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_destination_command_write(BYTE* buffer, UINT32 Destination)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_DESTINATION; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = Destination;         /* Destination (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_ping_traffic_sent_notify_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	/* PingTrafficSent (4 bytes) */
Packit 1fb8d4
	return 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_ping_traffic_sent_notify_command_write(BYTE* buffer, UINT32 PingTrafficSent)
Packit 1fb8d4
{
Packit 1fb8d4
	if (buffer)
Packit 1fb8d4
	{
Packit Service 5a9772
		*((UINT32*)&buffer[0]) = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY; /* CommandType (4 bytes) */
Packit Service 5a9772
		*((UINT32*)&buffer[4]) = PingTrafficSent;                  /* PingTrafficSent (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 8;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void rts_generate_cookie(BYTE* cookie)
Packit 1fb8d4
{
Packit 1fb8d4
	winpr_RAND(cookie, 16);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* CONN/A Sequence */
Packit 1fb8d4
Packit 1fb8d4
int rts_send_CONN_A1_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	UINT32 ReceiveWindowSize;
Packit 1fb8d4
	BYTE* OUTChannelCookie;
Packit 1fb8d4
	BYTE* VirtualConnectionCookie;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	RpcOutChannel* outChannel = connection->DefaultOutChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 76;
Packit 1fb8d4
	header.Flags = RTS_FLAG_NONE;
Packit 1fb8d4
	header.NumberOfCommands = 4;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending CONN/A1 RTS PDU");
Packit Service 5a9772
	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
Packit Service 5a9772
	OUTChannelCookie = (BYTE*)&(outChannel->common.Cookie);
Packit 1fb8d4
	ReceiveWindowSize = outChannel->ReceiveWindow;
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit Service 5a9772
	rts_version_command_write(&buffer[20]);   /* Version (8 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[28],
Packit 1fb8d4
	                         VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[48], OUTChannelCookie); /* OUTChannelCookie (20 bytes) */
Packit 1fb8d4
	rts_receive_window_size_command_write(&buffer[68],
Packit 1fb8d4
	                                      ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
Packit 1fb8d4
	status = rpc_channel_write(&outChannel->common, buffer, header.frag_length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rts_recv_CONN_A3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 ConnectionTimeout;
Packit 1fb8d4
	rts_connection_timeout_command_read(rpc, &buffer[24], length - 24, &ConnectionTimeout);
Packit Service 5a9772
	WLog_DBG(TAG, "Receiving CONN/A3 RTS PDU: ConnectionTimeout: %" PRIu32 "", ConnectionTimeout);
Packit 1fb8d4
	rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* CONN/B Sequence */
Packit 1fb8d4
Packit 1fb8d4
int rts_send_CONN_B1_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	UINT32 length;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	BYTE* INChannelCookie;
Packit 1fb8d4
	BYTE* AssociationGroupId;
Packit 1fb8d4
	BYTE* VirtualConnectionCookie;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	RpcInChannel* inChannel = connection->DefaultInChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 104;
Packit 1fb8d4
	header.Flags = RTS_FLAG_NONE;
Packit 1fb8d4
	header.NumberOfCommands = 6;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending CONN/B1 RTS PDU");
Packit Service 5a9772
	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
Packit Service 5a9772
	INChannelCookie = (BYTE*)&(inChannel->common.Cookie);
Packit Service 5a9772
	AssociationGroupId = (BYTE*)&(connection->AssociationGroupId);
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit Service 5a9772
	rts_version_command_write(&buffer[20]);   /* Version (8 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[28],
Packit Service 5a9772
	                         VirtualConnectionCookie);      /* VirtualConnectionCookie (20 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[48], INChannelCookie); /* INChannelCookie (20 bytes) */
Packit 1fb8d4
	rts_channel_lifetime_command_write(&buffer[68],
Packit 1fb8d4
	                                   rpc->ChannelLifetime); /* ChannelLifetime (8 bytes) */
Packit 1fb8d4
	rts_client_keepalive_command_write(&buffer[76],
Packit 1fb8d4
	                                   rpc->KeepAliveInterval); /* ClientKeepalive (8 bytes) */
Packit 1fb8d4
	rts_association_group_id_command_write(&buffer[84],
Packit 1fb8d4
	                                       AssociationGroupId); /* AssociationGroupId (20 bytes) */
Packit 1fb8d4
	length = header.frag_length;
Packit 1fb8d4
	status = rpc_channel_write(&inChannel->common, buffer, length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* CONN/C Sequence */
Packit 1fb8d4
Packit 1fb8d4
int rts_recv_CONN_C2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 offset;
Packit 1fb8d4
	UINT32 ReceiveWindowSize;
Packit 1fb8d4
	UINT32 ConnectionTimeout;
Packit 1fb8d4
	offset = 24;
Packit 1fb8d4
	offset += rts_version_command_read(rpc, &buffer[offset], length - offset) + 4;
Packit 1fb8d4
	offset += rts_receive_window_size_command_read(rpc, &buffer[offset], length - offset,
Packit Service 5a9772
	                                               &ReceiveWindowSize) +
Packit Service 5a9772
	          4;
Packit 1fb8d4
	offset += rts_connection_timeout_command_read(rpc, &buffer[offset], length - offset,
Packit Service 5a9772
	                                              &ConnectionTimeout) +
Packit Service 5a9772
	          4;
Packit 1fb8d4
	WLog_DBG(TAG,
Packit Service 5a9772
	         "Receiving CONN/C2 RTS PDU: ConnectionTimeout: %" PRIu32 " ReceiveWindowSize: %" PRIu32
Packit Service 5a9772
	         "",
Packit 1fb8d4
	         ConnectionTimeout, ReceiveWindowSize);
Packit 1fb8d4
	rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
Packit 1fb8d4
	rpc->VirtualConnection->DefaultInChannel->PeerReceiveWindow = ReceiveWindowSize;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Out-of-Sequence PDUs */
Packit 1fb8d4
Packit 1fb8d4
static int rts_send_keep_alive_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	UINT32 length;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 28;
Packit 1fb8d4
	header.Flags = RTS_FLAG_OTHER_CMD;
Packit 1fb8d4
	header.NumberOfCommands = 1;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending Keep-Alive RTS PDU");
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit Service 5a9772
	rts_client_keepalive_command_write(
Packit Service 5a9772
	    &buffer[20], rpc->CurrentKeepAliveInterval); /* ClientKeepAlive (8 bytes) */
Packit 1fb8d4
	length = header.frag_length;
Packit 1fb8d4
	status = rpc_channel_write(&inChannel->common, buffer, length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rts_send_flow_control_ack_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	UINT32 length;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	UINT32 BytesReceived;
Packit 1fb8d4
	UINT32 AvailableWindow;
Packit 1fb8d4
	BYTE* ChannelCookie;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	RpcInChannel* inChannel = connection->DefaultInChannel;
Packit 1fb8d4
	RpcOutChannel* outChannel = connection->DefaultOutChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 56;
Packit 1fb8d4
	header.Flags = RTS_FLAG_OTHER_CMD;
Packit 1fb8d4
	header.NumberOfCommands = 2;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending FlowControlAck RTS PDU");
Packit 1fb8d4
	BytesReceived = outChannel->BytesReceived;
Packit 1fb8d4
	AvailableWindow = outChannel->AvailableWindowAdvertised;
Packit Service 5a9772
	ChannelCookie = (BYTE*)&(outChannel->common.Cookie);
Packit 1fb8d4
	outChannel->ReceiverAvailableWindow = outChannel->AvailableWindowAdvertised;
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20);               /* RTS Header (20 bytes) */
Packit 1fb8d4
	rts_destination_command_write(&buffer[20], FDOutProxy); /* Destination Command (8 bytes) */
Packit 1fb8d4
	/* FlowControlAck Command (28 bytes) */
Packit 1fb8d4
	rts_flow_control_ack_command_write(&buffer[28], BytesReceived, AvailableWindow, ChannelCookie);
Packit 1fb8d4
	length = header.frag_length;
Packit 1fb8d4
	status = rpc_channel_write(&inChannel->common, buffer, length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 offset;
Packit 1fb8d4
	UINT32 BytesReceived;
Packit 1fb8d4
	UINT32 AvailableWindow;
Packit 1fb8d4
	BYTE ChannelCookie[16];
Packit 1fb8d4
	offset = 24;
Packit Service 5a9772
	offset +=
Packit Service 5a9772
	    rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset, &BytesReceived,
Packit Service 5a9772
	                                      &AvailableWindow, (BYTE*)&ChannelCookie) +
Packit Service 5a9772
	    4;
Packit 1fb8d4
	WLog_ERR(TAG,
Packit Service 5a9772
	         "Receiving FlowControlAck RTS PDU: BytesReceived: %" PRIu32
Packit Service 5a9772
	         " AvailableWindow: %" PRIu32 "",
Packit 1fb8d4
	         BytesReceived, AvailableWindow);
Packit 1fb8d4
	rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
Packit 1fb8d4
	    AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 offset;
Packit 1fb8d4
	UINT32 Destination;
Packit 1fb8d4
	UINT32 BytesReceived;
Packit 1fb8d4
	UINT32 AvailableWindow;
Packit 1fb8d4
	BYTE ChannelCookie[16];
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * When the sender receives a FlowControlAck RTS PDU, it MUST use the following formula to
Packit 1fb8d4
	 * recalculate its Sender AvailableWindow variable:
Packit 1fb8d4
	 *
Packit Service 5a9772
	 * Sender AvailableWindow = Receiver AvailableWindow_from_ack - (BytesSent -
Packit Service 5a9772
	 * BytesReceived_from_ack)
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * Where:
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * Receiver AvailableWindow_from_ack is the Available Window field in the Flow Control
Packit 1fb8d4
	 * Acknowledgement Structure (section 2.2.3.4) in the PDU received.
Packit 1fb8d4
	 *
Packit Service 5a9772
	 * BytesReceived_from_ack is the Bytes Received field in the Flow Control Acknowledgement
Packit Service 5a9772
	 * structure in the PDU received.
Packit 1fb8d4
	 *
Packit 1fb8d4
	 */
Packit 1fb8d4
	offset = 24;
Packit 1fb8d4
	offset += rts_destination_command_read(rpc, &buffer[offset], length - offset, &Destination) + 4;
Packit Service 5a9772
	offset +=
Packit Service 5a9772
	    rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset, &BytesReceived,
Packit Service 5a9772
	                                      &AvailableWindow, (BYTE*)&ChannelCookie) +
Packit Service 5a9772
	    4;
Packit 1fb8d4
	WLog_DBG(TAG,
Packit Service 5a9772
	         "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %" PRIu32
Packit Service 5a9772
	         " AvailableWindow: %" PRIu32 "",
Packit 1fb8d4
	         BytesReceived, AvailableWindow);
Packit 1fb8d4
	rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
Packit 1fb8d4
	    AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_send_ping_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	UINT32 length;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 20;
Packit 1fb8d4
	header.Flags = RTS_FLAG_PING;
Packit 1fb8d4
	header.NumberOfCommands = 0;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending Ping RTS PDU");
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit 1fb8d4
	length = header.frag_length;
Packit 1fb8d4
	status = rpc_channel_write(&inChannel->common, buffer, length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	int CommandLength = 0;
Packit 1fb8d4
Packit 1fb8d4
	switch (CommandType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RTS_CMD_RECEIVE_WINDOW_SIZE:
Packit 1fb8d4
			CommandLength = RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_FLOW_CONTROL_ACK:
Packit 1fb8d4
			CommandLength = RTS_CMD_FLOW_CONTROL_ACK_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_CONNECTION_TIMEOUT:
Packit 1fb8d4
			CommandLength = RTS_CMD_CONNECTION_TIMEOUT_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_COOKIE:
Packit 1fb8d4
			CommandLength = RTS_CMD_COOKIE_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_CHANNEL_LIFETIME:
Packit 1fb8d4
			CommandLength = RTS_CMD_CHANNEL_LIFETIME_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_CLIENT_KEEPALIVE:
Packit Service 5a9772
			CommandLength = RTS_CMD_CLIENT_KEEPALIVE_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_VERSION:
Packit 1fb8d4
			CommandLength = RTS_CMD_VERSION_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_EMPTY:
Packit 1fb8d4
			CommandLength = RTS_CMD_EMPTY_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_PADDING: /* variable-size */
Packit 1fb8d4
			CommandLength = rts_padding_command_read(buffer, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_NEGATIVE_ANCE:
Packit 1fb8d4
			CommandLength = RTS_CMD_NEGATIVE_ANCE_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_ANCE:
Packit 1fb8d4
			CommandLength = RTS_CMD_ANCE_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_CLIENT_ADDRESS: /* variable-size */
Packit 1fb8d4
			CommandLength = rts_client_address_command_read(buffer, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_ASSOCIATION_GROUP_ID:
Packit 1fb8d4
			CommandLength = RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_DESTINATION:
Packit 1fb8d4
			CommandLength = RTS_CMD_DESTINATION_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CMD_PING_TRAFFIC_SENT_NOTIFY:
Packit 1fb8d4
			CommandLength = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			WLog_ERR(TAG, "Error: Unknown RTS Command Type: 0x%" PRIx32 "", CommandType);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CommandLength;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	BYTE* SuccessorChannelCookie;
Packit 1fb8d4
	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
Packit 1fb8d4
	RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 56;
Packit 1fb8d4
	header.Flags = RTS_FLAG_OUT_CHANNEL;
Packit 1fb8d4
	header.NumberOfCommands = 3;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending OUT_R2/A7 RTS PDU");
Packit Service 5a9772
	SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20);             /* RTS Header (20 bytes) */
Packit 1fb8d4
	rts_destination_command_write(&buffer[20], FDServer); /* Destination (8 bytes)*/
Packit 1fb8d4
	rts_cookie_command_write(&buffer[28],
Packit 1fb8d4
	                         SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
Packit Service 5a9772
	rts_version_command_write(&buffer[48]);           /* Version (8 bytes) */
Packit 1fb8d4
	status = rpc_channel_write(&inChannel->common, buffer, header.frag_length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 24;
Packit 1fb8d4
	header.Flags = RTS_FLAG_PING;
Packit 1fb8d4
	header.NumberOfCommands = 1;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending OUT_R2/C1 RTS PDU");
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit Service 5a9772
	rts_empty_command_write(&buffer[20]);     /* Empty command (4 bytes) */
Packit 1fb8d4
	status = rpc_channel_write(&nextOutChannel->common, buffer, header.frag_length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	rpcconn_rts_hdr_t header;
Packit 1fb8d4
	UINT32 ReceiveWindowSize;
Packit 1fb8d4
	BYTE* VirtualConnectionCookie;
Packit 1fb8d4
	BYTE* PredecessorChannelCookie;
Packit 1fb8d4
	BYTE* SuccessorChannelCookie;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	RpcOutChannel* outChannel = connection->DefaultOutChannel;
Packit 1fb8d4
	RpcOutChannel* nextOutChannel = connection->NonDefaultOutChannel;
Packit 1fb8d4
	rts_pdu_header_init(&header);
Packit 1fb8d4
	header.frag_length = 96;
Packit 1fb8d4
	header.Flags = RTS_FLAG_RECYCLE_CHANNEL;
Packit 1fb8d4
	header.NumberOfCommands = 5;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending OUT_R1/A3 RTS PDU");
Packit Service 5a9772
	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
Packit Service 5a9772
	PredecessorChannelCookie = (BYTE*)&(outChannel->common.Cookie);
Packit Service 5a9772
	SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
Packit 1fb8d4
	ReceiveWindowSize = outChannel->ReceiveWindow;
Packit Service 5a9772
	buffer = (BYTE*)malloc(header.frag_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
Packit Service 5a9772
	rts_version_command_write(&buffer[20]);   /* Version (8 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[28],
Packit 1fb8d4
	                         VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[48],
Packit 1fb8d4
	                         PredecessorChannelCookie); /* PredecessorChannelCookie (20 bytes) */
Packit 1fb8d4
	rts_cookie_command_write(&buffer[68],
Packit 1fb8d4
	                         SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
Packit 1fb8d4
	rts_receive_window_size_command_write(&buffer[88],
Packit 1fb8d4
	                                      ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
Packit 1fb8d4
	status = rpc_channel_write(&nextOutChannel->common, buffer, header.frag_length);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return (status > 0) ? 1 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	UINT32 offset;
Packit 1fb8d4
	UINT32 Destination = 0;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	WLog_DBG(TAG, "Receiving OUT R1/A2 RTS PDU");
Packit 1fb8d4
	offset = 24;
Packit 1fb8d4
Packit 1fb8d4
	if (length < offset)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	rts_destination_command_read(rpc, &buffer[offset], length - offset, &Destination);
Packit 1fb8d4
	connection->NonDefaultOutChannel = rpc_out_channel_new(rpc);
Packit 1fb8d4
Packit 1fb8d4
	if (!connection->NonDefaultOutChannel)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	status = rpc_out_channel_replacement_connect(connection->NonDefaultOutChannel, 5000);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rpc_out_channel_replacement_connect failure");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
Packit 1fb8d4
	                                    CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	WLog_DBG(TAG, "Receiving OUT R2/A6 RTS PDU");
Packit 1fb8d4
	status = rts_send_OUT_R2_C1_pdu(rpc);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rts_send_OUT_R2_C1_pdu failure");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = rts_send_OUT_R2_A7_pdu(rpc);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "rts_send_OUT_R2_A7_pdu failure");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rpc_out_channel_transition_to_state(connection->NonDefaultOutChannel,
Packit 1fb8d4
	                                    CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
Packit 1fb8d4
	rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
Packit 1fb8d4
	                                    CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	RpcVirtualConnection* connection = rpc->VirtualConnection;
Packit 1fb8d4
	WLog_DBG(TAG, "Receiving OUT R2/B3 RTS PDU");
Packit 1fb8d4
	rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
Packit 1fb8d4
	                                    CLIENT_OUT_CHANNEL_STATE_RECYCLED);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit 1fb8d4
	UINT32 SignatureId;
Packit 1fb8d4
	rpcconn_rts_hdr_t* rts;
Packit 1fb8d4
	RtsPduSignature signature;
Packit 1fb8d4
	RpcVirtualConnection* connection;
Packit 1fb8d4
Packit 1fb8d4
	if (!rpc || !buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	connection = rpc->VirtualConnection;
Packit 1fb8d4
Packit 1fb8d4
	if (!connection)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	rts = (rpcconn_rts_hdr_t*)buffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!rts_extract_pdu_signature(&signature, rts))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	SignatureId = rts_identify_pdu_signature(&signature, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, rts))
Packit 1fb8d4
	{
Packit 1fb8d4
		status = rts_recv_flow_control_ack_pdu(rpc, buffer, length);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, rts))
Packit 1fb8d4
	{
Packit 1fb8d4
		status = rts_recv_flow_control_ack_with_destination_pdu(rpc, buffer, length);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (rts_match_pdu_signature(&RTS_PDU_PING_SIGNATURE, rts))
Packit 1fb8d4
	{
Packit 1fb8d4
		status = rts_send_ping_pdu(rpc);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (rts_match_pdu_signature(&RTS_PDU_OUT_R1_A2_SIGNATURE, rts))
Packit 1fb8d4
			{
Packit 1fb8d4
				status = rts_recv_OUT_R1_A2_pdu(rpc, buffer, length);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_A6W)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_A6_SIGNATURE, rts))
Packit 1fb8d4
			{
Packit 1fb8d4
				status = rts_recv_OUT_R2_A6_pdu(rpc, buffer, length);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_B3W)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_B3_SIGNATURE, rts))
Packit 1fb8d4
			{
Packit 1fb8d4
				status = rts_recv_OUT_R2_B3_pdu(rpc, buffer, length);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "error parsing RTS PDU with signature id: 0x%08" PRIX32 "", SignatureId);
Packit 1fb8d4
		rts_print_pdu_signature(&signature);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}