Blame libfreerdp/core/autodetect.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Auto-Detect PDUs
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Dell Software <Mike.McDonald@software.dell.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/crypto.h>
Packit 1fb8d4
Packit 1fb8d4
#include "autodetect.h"
Packit 1fb8d4
Packit Service 5a9772
#define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001
Packit 1fb8d4
#define RDP_RTT_REQUEST_TYPE_CONNECTTIME 0x1001
Packit 1fb8d4
Packit 1fb8d4
#define RDP_RTT_RESPONSE_TYPE 0x0000
Packit 1fb8d4
Packit Service 5a9772
#define RDP_BW_START_REQUEST_TYPE_CONTINUOUS 0x0014
Packit Service 5a9772
#define RDP_BW_START_REQUEST_TYPE_TUNNEL 0x0114
Packit 1fb8d4
#define RDP_BW_START_REQUEST_TYPE_CONNECTTIME 0x1014
Packit Service 5a9772
#define RDP_BW_PAYLOAD_REQUEST_TYPE 0x0002
Packit Service 5a9772
#define RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME 0x002B
Packit Service 5a9772
#define RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS 0x0429
Packit Service 5a9772
#define RDP_BW_STOP_REQUEST_TYPE_TUNNEL 0x0629
Packit 1fb8d4
Packit 1fb8d4
#define RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME 0x0003
Packit Service 5a9772
#define RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS 0x000B
Packit 1fb8d4
Packit 1fb8d4
#define RDP_NETCHAR_SYNC_RESPONSE_TYPE 0x0018
Packit 1fb8d4
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit 1fb8d4
	UINT8 headerLength;
Packit 1fb8d4
	UINT8 headerTypeId;
Packit 1fb8d4
	UINT16 sequenceNumber;
Packit 1fb8d4
	UINT16 requestType;
Packit 1fb8d4
} AUTODETECT_REQ_PDU;
Packit 1fb8d4
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit 1fb8d4
	UINT8 headerLength;
Packit 1fb8d4
	UINT8 headerTypeId;
Packit 1fb8d4
	UINT16 sequenceNumber;
Packit 1fb8d4
	UINT16 responseType;
Packit 1fb8d4
} AUTODETECT_RSP_PDU;
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_rtt_measure_request(rdpContext* context, UINT16 sequenceNumber,
Packit Service 5a9772
                                                UINT16 requestType)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(context->rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "sending RTT Measure Request PDU");
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x06);                       /* headerLength (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);            /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, requestType);               /* requestType (2 bytes) */
Packit Service 5a9772
	context->rdp->autodetect->rttMeasureStartTime = GetTickCount64();
Packit 1fb8d4
	return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_continuous_rtt_measure_request(rdpContext* context,
Packit Service 5a9772
                                                           UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_rtt_measure_request(context, sequenceNumber,
Packit Service 5a9772
	                                           RDP_RTT_REQUEST_TYPE_CONTINUOUS);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL autodetect_send_connecttime_rtt_measure_request(rdpContext* context, UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_rtt_measure_request(context, sequenceNumber,
Packit Service 5a9772
	                                           RDP_RTT_REQUEST_TYPE_CONNECTTIME);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_rtt_measure_response(rdpRdp* rdp, UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	/* Send the response PDU to the server */
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "sending RTT Measure Response PDU");
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x06);                        /* headerLength (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);             /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, RDP_RTT_RESPONSE_TYPE);      /* responseType (1 byte) */
Packit 1fb8d4
	return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_bandwidth_measure_start(rdpContext* context, UINT16 sequenceNumber,
Packit Service 5a9772
                                                    UINT16 requestType)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(context->rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Start PDU");
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x06);                       /* headerLength (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);            /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, requestType);               /* requestType (2 bytes) */
Packit 1fb8d4
	return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_continuous_bandwidth_measure_start(rdpContext* context,
Packit Service 5a9772
                                                               UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_bandwidth_measure_start(context, sequenceNumber,
Packit Service 5a9772
	                                               RDP_BW_START_REQUEST_TYPE_CONTINUOUS);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL autodetect_send_connecttime_bandwidth_measure_start(rdpContext* context, UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_bandwidth_measure_start(context, sequenceNumber,
Packit Service 5a9772
	                                               RDP_BW_START_REQUEST_TYPE_CONNECTTIME);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL autodetect_send_bandwidth_measure_payload(rdpContext* context, UINT16 payloadLength,
Packit Service 5a9772
                                               UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	UCHAR* buffer = NULL;
Packit 1fb8d4
	BOOL bResult = FALSE;
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(context->rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "",
Packit 1fb8d4
	         payloadLength);
Packit 1fb8d4
	/* 4-bytes aligned */
Packit 1fb8d4
	payloadLength &= ~3;
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, 8 + payloadLength))
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Release(s);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x08);                         /* headerLength (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);   /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);              /* sequenceNumber (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, RDP_BW_PAYLOAD_REQUEST_TYPE); /* requestType (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, payloadLength);               /* payloadLength (2 bytes) */
Packit 1fb8d4
	/* Random data (better measurement in case the line is compressed) */
Packit 1fb8d4
	buffer = (UCHAR*)malloc(payloadLength);
Packit 1fb8d4
Packit 1fb8d4
	if (NULL == buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Release(s);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	winpr_RAND(buffer, payloadLength);
Packit 1fb8d4
	Stream_Write(s, buffer, payloadLength);
Packit 1fb8d4
	bResult = rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return bResult;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_bandwidth_measure_stop(rdpContext* context, UINT16 payloadLength,
Packit Service 5a9772
                                                   UINT16 sequenceNumber, UINT16 requestType)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	UCHAR* buffer = NULL;
Packit 1fb8d4
	BOOL bResult = FALSE;
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(context->rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "",
Packit 1fb8d4
	         payloadLength);
Packit 1fb8d4
	/* 4-bytes aligned */
Packit 1fb8d4
	payloadLength &= ~3;
Packit Service 5a9772
	Stream_Write_UINT8(s, requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
Packit Service 5a9772
	                          ? 0x08
Packit Service 5a9772
	                          : 0x06);                 /* headerLength (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);            /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, requestType);               /* requestType (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
		if (payloadLength > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(s, payloadLength))
Packit 1fb8d4
			{
Packit 1fb8d4
				Stream_Release(s);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* Random data (better measurement in case the line is compressed) */
Packit 1fb8d4
			buffer = malloc(payloadLength);
Packit 1fb8d4
Packit 1fb8d4
			if (NULL == buffer)
Packit 1fb8d4
			{
Packit 1fb8d4
				Stream_Release(s);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			winpr_RAND(buffer, payloadLength);
Packit 1fb8d4
			Stream_Write(s, buffer, payloadLength);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	bResult = rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return bResult;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_continuous_bandwidth_measure_stop(rdpContext* context,
Packit Service 5a9772
                                                              UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_bandwidth_measure_stop(context, 0, sequenceNumber,
Packit Service 5a9772
	                                              RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL autodetect_send_connecttime_bandwidth_measure_stop(rdpContext* context, UINT16 payloadLength,
Packit Service 5a9772
                                                        UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	return autodetect_send_bandwidth_measure_stop(context, payloadLength, sequenceNumber,
Packit Service 5a9772
	                                              RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_bandwidth_measure_results(rdpRdp* rdp, UINT16 responseType,
Packit Service 5a9772
                                                      UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL success = TRUE;
Packit 1fb8d4
	wStream* s;
Packit Service 5a9772
	UINT64 timeDelta;
Packit 1fb8d4
	/* Compute the total time */
Packit Service 5a9772
	timeDelta = GetTickCount64() - rdp->autodetect->bandwidthMeasureStartTime;
Packit 1fb8d4
	/* Send the result PDU to the server */
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG,
Packit Service 5a9772
	         "sending Bandwidth Measure Results PDU -> timeDelta=%" PRIu32 ", byteCount=%" PRIu32
Packit Service 5a9772
	         "",
Packit Service 5a9772
	         timeDelta, rdp->autodetect->bandwidthMeasureByteCount);
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x0E);                        /* headerLength (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);             /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, responseType);               /* responseType (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT32(s, timeDelta);                  /* timeDelta (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, rdp->autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
Packit Service 5a9772
	IFCALLRET(rdp->autodetect->ClientBandwidthMeasureResult, success, rdp->context,
Packit Service 5a9772
	          rdp->autodetect);
Packit 1fb8d4
Packit 1fb8d4
	if (!success)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_send_netchar_result(rdpContext* context, UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(context->rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Network Characteristics Result PDU");
Packit 1fb8d4
Packit 1fb8d4
	if (context->rdp->autodetect->netCharBandwidth > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		Stream_Write_UINT8(s, 0x12);                       /* headerLength (1 byte) */
Packit 1fb8d4
		Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
Packit Service 5a9772
		Stream_Write_UINT16(s, sequenceNumber);            /* sequenceNumber (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, 0x08C0);                    /* requestType (2 bytes) */
Packit 1fb8d4
		Stream_Write_UINT32(s, context->rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s,
Packit Service 5a9772
		                    context->rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s,
Packit Service 5a9772
		                    context->rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		Stream_Write_UINT8(s, 0x0E);                       /* headerLength (1 byte) */
Packit 1fb8d4
		Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
Packit Service 5a9772
		Stream_Write_UINT16(s, sequenceNumber);            /* sequenceNumber (2 bytes) */
Packit Service 5a9772
		Stream_Write_UINT16(s, 0x0840);                    /* requestType (2 bytes) */
Packit 1fb8d4
		Stream_Write_UINT32(s, context->rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
Packit Service 5a9772
		Stream_Write_UINT32(s,
Packit Service 5a9772
		                    context->rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL autodetect_send_netchar_sync(rdpRdp* rdp, UINT16 sequenceNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	/* Send the response PDU to the server */
Packit 1fb8d4
	s = rdp_message_channel_pdu_init(rdp);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG,
Packit Service 5a9772
	         "sending Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32 "",
Packit 1fb8d4
	         rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT);
Packit Service 5a9772
	Stream_Write_UINT8(s, 0x0E);                                /* headerLength (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE);         /* headerTypeId (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT16(s, sequenceNumber);                     /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Write_UINT16(s, RDP_NETCHAR_SYNC_RESPONSE_TYPE);     /* responseType (1 byte) */
Packit Service 5a9772
	Stream_Write_UINT32(s, rdp->autodetect->netCharBandwidth);  /* bandwidth (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, rdp->autodetect->netCharAverageRTT); /* rtt (4 bytes) */
Packit 1fb8d4
	return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_rtt_measure_request(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                AUTODETECT_REQ_PDU* autodetectReqPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	if (autodetectReqPdu->headerLength != 0x06)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "received RTT Measure Request PDU");
Packit 1fb8d4
	/* Send a response to the server */
Packit 1fb8d4
	return autodetect_send_rtt_measure_response(rdp, autodetectReqPdu->sequenceNumber);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_rtt_measure_response(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                 AUTODETECT_RSP_PDU* autodetectRspPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL success = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectRspPdu->headerLength != 0x06)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "received RTT Measure Response PDU");
Packit Service 5a9772
	rdp->autodetect->netCharAverageRTT = GetTickCount64() - rdp->autodetect->rttMeasureStartTime;
Packit 1fb8d4
Packit 1fb8d4
	if (rdp->autodetect->netCharBaseRTT == 0 ||
Packit 1fb8d4
	    rdp->autodetect->netCharBaseRTT > rdp->autodetect->netCharAverageRTT)
Packit 1fb8d4
		rdp->autodetect->netCharBaseRTT = rdp->autodetect->netCharAverageRTT;
Packit 1fb8d4
Packit 1fb8d4
	IFCALLRET(rdp->autodetect->RTTMeasureResponse, success, rdp->context,
Packit 1fb8d4
	          autodetectRspPdu->sequenceNumber);
Packit 1fb8d4
	return success;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_bandwidth_measure_start(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                    AUTODETECT_REQ_PDU* autodetectReqPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	if (autodetectReqPdu->headerLength != 0x06)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Start PDU - time=%" PRIu64 "",
Packit Service 5a9772
	         GetTickCount64());
Packit 1fb8d4
	/* Initialize bandwidth measurement parameters */
Packit Service 5a9772
	rdp->autodetect->bandwidthMeasureStartTime = GetTickCount64();
Packit 1fb8d4
	rdp->autodetect->bandwidthMeasureByteCount = 0;
Packit 1fb8d4
Packit 1fb8d4
	/* Continuous Auto-Detection: mark the start of the measurement */
Packit 1fb8d4
	if (autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONTINUOUS)
Packit 1fb8d4
	{
Packit 1fb8d4
		rdp->autodetect->bandwidthMeasureStarted = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_bandwidth_measure_payload(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                      AUTODETECT_REQ_PDU* autodetectReqPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 payloadLength;
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectReqPdu->headerLength != 0x08)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 2)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
Packit Service 5a9772
	if (!Stream_SafeSeek(s, payloadLength))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	WLog_DBG(AUTODETECT_TAG, "received Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "",
Packit 1fb8d4
	         payloadLength);
Packit 1fb8d4
	/* Add the payload length to the bandwidth measurement parameters */
Packit 1fb8d4
	rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_bandwidth_measure_stop(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                   AUTODETECT_REQ_PDU* autodetectReqPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 payloadLength;
Packit 1fb8d4
	UINT16 responseType;
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (autodetectReqPdu->headerLength != 0x08)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (Stream_GetRemainingLength(s) < 2)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (autodetectReqPdu->headerLength != 0x06)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		payloadLength = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!Stream_SafeSeek(s, payloadLength))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "",
Packit 1fb8d4
	         payloadLength);
Packit 1fb8d4
	/* Add the payload length to the bandwidth measurement parameters */
Packit 1fb8d4
	rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
Packit 1fb8d4
Packit 1fb8d4
	/* Continuous Auto-Detection: mark the stop of the measurement */
Packit 1fb8d4
	if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
Packit 1fb8d4
	{
Packit 1fb8d4
		rdp->autodetect->bandwidthMeasureStarted = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Send a response the server */
Packit Service 5a9772
	responseType = autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
Packit Service 5a9772
	                   ? RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME
Packit Service 5a9772
	                   : RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS;
Packit 1fb8d4
	return autodetect_send_bandwidth_measure_results(rdp, responseType,
Packit Service 5a9772
	                                                 autodetectReqPdu->sequenceNumber);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_bandwidth_measure_results(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                                      AUTODETECT_RSP_PDU* autodetectRspPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL success = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectRspPdu->headerLength != 0x0E)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Results PDU");
Packit Service 5a9772
	if (Stream_GetRemainingLength(s) < 8)
Packit Service 5a9772
		return -1;
Packit 1fb8d4
	Stream_Read_UINT32(s, rdp->autodetect->bandwidthMeasureTimeDelta); /* timeDelta (4 bytes) */
Packit 1fb8d4
	Stream_Read_UINT32(s, rdp->autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (rdp->autodetect->bandwidthMeasureTimeDelta > 0)
Packit 1fb8d4
		rdp->autodetect->netCharBandwidth = rdp->autodetect->bandwidthMeasureByteCount * 8 /
Packit 1fb8d4
		                                    rdp->autodetect->bandwidthMeasureTimeDelta;
Packit 1fb8d4
	else
Packit 1fb8d4
		rdp->autodetect->netCharBandwidth = 0;
Packit 1fb8d4
Packit 1fb8d4
	IFCALLRET(rdp->autodetect->BandwidthMeasureResults, success, rdp->context,
Packit 1fb8d4
	          autodetectRspPdu->sequenceNumber);
Packit 1fb8d4
	return success;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL autodetect_recv_netchar_result(rdpRdp* rdp, wStream* s,
Packit Service 5a9772
                                           AUTODETECT_REQ_PDU* autodetectReqPdu)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL success = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	switch (autodetectReqPdu->requestType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case 0x0840:
Packit 1fb8d4
Packit 1fb8d4
			/* baseRTT and averageRTT fields are present (bandwidth field is not) */
Packit 1fb8d4
			if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit Service 5a9772
			Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT);    /* baseRTT (4 bytes) */
Packit 1fb8d4
			Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case 0x0880:
Packit 1fb8d4
Packit 1fb8d4
			/* bandwidth and averageRTT fields are present (baseRTT field is not) */
Packit 1fb8d4
			if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit Service 5a9772
			Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth);  /* bandwidth (4 bytes) */
Packit 1fb8d4
			Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case 0x08C0:
Packit 1fb8d4
Packit 1fb8d4
			/* baseRTT, bandwidth, and averageRTT fields are present */
Packit 1fb8d4
			if ((autodetectReqPdu->headerLength != 0x12) || (Stream_GetRemainingLength(s) < 12))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit Service 5a9772
			Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT);    /* baseRTT (4 bytes) */
Packit Service 5a9772
			Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth);  /* bandwidth (4 bytes) */
Packit 1fb8d4
			Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG,
Packit Service 5a9772
	         "received Network Characteristics Result PDU -> baseRTT=%" PRIu32
Packit Service 5a9772
	         ", bandwidth=%" PRIu32 ", averageRTT=%" PRIu32 "",
Packit 1fb8d4
	         rdp->autodetect->netCharBaseRTT, rdp->autodetect->netCharBandwidth,
Packit 1fb8d4
	         rdp->autodetect->netCharAverageRTT);
Packit 1fb8d4
	IFCALLRET(rdp->autodetect->NetworkCharacteristicsResult, success, rdp->context,
Packit 1fb8d4
	          autodetectReqPdu->sequenceNumber);
Packit 1fb8d4
	return success;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rdp_recv_autodetect_request_packet(rdpRdp* rdp, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	AUTODETECT_REQ_PDU autodetectReqPdu;
Packit 1fb8d4
	BOOL success = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 6)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Read_UINT8(s, autodetectReqPdu.headerLength);    /* headerLength (1 byte) */
Packit Service 5a9772
	Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId);    /* headerTypeId (1 byte) */
Packit 1fb8d4
	Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Read_UINT16(s, autodetectReqPdu.requestType);    /* requestType (2 bytes) */
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG,
Packit Service 5a9772
	         "rdp_recv_autodetect_request_packet: headerLength=%" PRIu8 ", headerTypeId=%" PRIu8
Packit Service 5a9772
	         ", sequenceNumber=%" PRIu16 ", requestType=%04" PRIx16 "",
Packit 1fb8d4
	         autodetectReqPdu.headerLength, autodetectReqPdu.headerTypeId,
Packit 1fb8d4
	         autodetectReqPdu.sequenceNumber, autodetectReqPdu.requestType);
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	switch (autodetectReqPdu.requestType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
Packit 1fb8d4
		case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
Packit 1fb8d4
			/* RTT Measure Request (RDP_RTT_REQUEST) - MS-RDPBCGR 2.2.14.1.1 */
Packit 1fb8d4
			success = autodetect_recv_rtt_measure_request(rdp, s, &autodetectReqPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
Packit 1fb8d4
		case RDP_BW_START_REQUEST_TYPE_TUNNEL:
Packit 1fb8d4
		case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
Packit 1fb8d4
			/* Bandwidth Measure Start (RDP_BW_START) - MS-RDPBCGR 2.2.14.1.2 */
Packit 1fb8d4
			success = autodetect_recv_bandwidth_measure_start(rdp, s, &autodetectReqPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDP_BW_PAYLOAD_REQUEST_TYPE:
Packit 1fb8d4
			/* Bandwidth Measure Payload (RDP_BW_PAYLOAD) - MS-RDPBCGR 2.2.14.1.3 */
Packit 1fb8d4
			success = autodetect_recv_bandwidth_measure_payload(rdp, s, &autodetectReqPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
Packit 1fb8d4
		case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
Packit 1fb8d4
		case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
Packit 1fb8d4
			/* Bandwidth Measure Stop (RDP_BW_STOP) - MS-RDPBCGR 2.2.14.1.4 */
Packit 1fb8d4
			success = autodetect_recv_bandwidth_measure_stop(rdp, s, &autodetectReqPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case 0x0840:
Packit 1fb8d4
		case 0x0880:
Packit 1fb8d4
		case 0x08C0:
Packit 1fb8d4
			/* Network Characteristics Result (RDP_NETCHAR_RESULT) - MS-RDPBCGR 2.2.14.1.5 */
Packit 1fb8d4
			success = autodetect_recv_netchar_result(rdp, s, &autodetectReqPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return success ? 0 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int rdp_recv_autodetect_response_packet(rdpRdp* rdp, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	AUTODETECT_RSP_PDU autodetectRspPdu;
Packit 1fb8d4
	BOOL success = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 6)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Read_UINT8(s, autodetectRspPdu.headerLength);    /* headerLength (1 byte) */
Packit Service 5a9772
	Stream_Read_UINT8(s, autodetectRspPdu.headerTypeId);    /* headerTypeId (1 byte) */
Packit 1fb8d4
	Stream_Read_UINT16(s, autodetectRspPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
Packit Service 5a9772
	Stream_Read_UINT16(s, autodetectRspPdu.responseType);   /* responseType (2 bytes) */
Packit 1fb8d4
	WLog_VRB(AUTODETECT_TAG,
Packit Service 5a9772
	         "rdp_recv_autodetect_response_packet: headerLength=%" PRIu8 ", headerTypeId=%" PRIu8
Packit Service 5a9772
	         ", sequenceNumber=%" PRIu16 ", requestType=%04" PRIx16 "",
Packit 1fb8d4
	         autodetectRspPdu.headerLength, autodetectRspPdu.headerTypeId,
Packit 1fb8d4
	         autodetectRspPdu.sequenceNumber, autodetectRspPdu.responseType);
Packit 1fb8d4
Packit 1fb8d4
	if (autodetectRspPdu.headerTypeId != TYPE_ID_AUTODETECT_RESPONSE)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	switch (autodetectRspPdu.responseType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RDP_RTT_RESPONSE_TYPE:
Packit 1fb8d4
			/* RTT Measure Response (RDP_RTT_RESPONSE) - MS-RDPBCGR 2.2.14.2.1 */
Packit 1fb8d4
			success = autodetect_recv_rtt_measure_response(rdp, s, &autodetectRspPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
Packit 1fb8d4
		case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
Packit 1fb8d4
			/* Bandwidth Measure Results (RDP_BW_RESULTS) - MS-RDPBCGR 2.2.14.2.2 */
Packit 1fb8d4
			success = autodetect_recv_bandwidth_measure_results(rdp, s, &autodetectRspPdu);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
	return success ? 0 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
rdpAutoDetect* autodetect_new(void)
Packit 1fb8d4
{
Packit Service 5a9772
	rdpAutoDetect* autoDetect = (rdpAutoDetect*)calloc(1, sizeof(rdpAutoDetect));
Packit 1fb8d4
Packit 1fb8d4
	if (autoDetect)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return autoDetect;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void autodetect_free(rdpAutoDetect* autoDetect)
Packit 1fb8d4
{
Packit 1fb8d4
	free(autoDetect);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void autodetect_register_server_callbacks(rdpAutoDetect* autodetect)
Packit 1fb8d4
{
Packit 1fb8d4
	autodetect->RTTMeasureRequest = autodetect_send_continuous_rtt_measure_request;
Packit 1fb8d4
	autodetect->BandwidthMeasureStart = autodetect_send_continuous_bandwidth_measure_start;
Packit 1fb8d4
	autodetect->BandwidthMeasureStop = autodetect_send_continuous_bandwidth_measure_stop;
Packit 1fb8d4
	autodetect->NetworkCharacteristicsResult = autodetect_send_netchar_result;
Packit 1fb8d4
}