1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Auto-Detect PDUs
4 *
5 * Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <winpr/crypto.h>
25
26 #include "autodetect.h"
27
28 #define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001
29 #define RDP_RTT_REQUEST_TYPE_CONNECTTIME 0x1001
30
31 #define RDP_RTT_RESPONSE_TYPE 0x0000
32
33 #define RDP_BW_START_REQUEST_TYPE_CONTINUOUS 0x0014
34 #define RDP_BW_START_REQUEST_TYPE_TUNNEL 0x0114
35 #define RDP_BW_START_REQUEST_TYPE_CONNECTTIME 0x1014
36 #define RDP_BW_PAYLOAD_REQUEST_TYPE 0x0002
37 #define RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME 0x002B
38 #define RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS 0x0429
39 #define RDP_BW_STOP_REQUEST_TYPE_TUNNEL 0x0629
40
41 #define RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME 0x0003
42 #define RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS 0x000B
43
44 #define RDP_NETCHAR_SYNC_RESPONSE_TYPE 0x0018
45
46 #define RDP_NETCHAR_RESULTS_0x0840 0x0840U
47 #define RDP_NETCHAR_RESULTS_0x0880 0x0880U
48 #define RDP_NETCHAR_RESULTS_0x08C0 0x08C0U
49
50 typedef struct
51 {
52 UINT8 headerLength;
53 UINT8 headerTypeId;
54 UINT16 sequenceNumber;
55 UINT16 requestType;
56 } AUTODETECT_REQ_PDU;
57
58 typedef struct
59 {
60 UINT8 headerLength;
61 UINT8 headerTypeId;
62 UINT16 sequenceNumber;
63 UINT16 responseType;
64 } AUTODETECT_RSP_PDU;
65
autodetect_request_type_to_string(UINT32 requestType)66 static const char* autodetect_request_type_to_string(UINT32 requestType)
67 {
68 switch (requestType)
69 {
70 case RDP_RTT_RESPONSE_TYPE:
71 return "RDP_RTT_RESPONSE_TYPE";
72 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
73 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME";
74 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
75 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS";
76 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
77 return "RDP_RTT_REQUEST_TYPE_CONTINUOUS";
78 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
79 return "RDP_RTT_REQUEST_TYPE_CONNECTTIME";
80 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
81 return "RDP_BW_START_REQUEST_TYPE_CONTINUOUS";
82 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
83 return "RDP_BW_START_REQUEST_TYPE_TUNNEL";
84 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
85 return "RDP_BW_START_REQUEST_TYPE_CONNECTTIME";
86 case RDP_BW_PAYLOAD_REQUEST_TYPE:
87 return "RDP_BW_PAYLOAD_REQUEST_TYPE";
88 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
89 return "RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME";
90 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
91 return "RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS";
92 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
93 return "RDP_BW_STOP_REQUEST_TYPE_TUNNEL";
94 case RDP_NETCHAR_RESULTS_0x0840:
95 return "RDP_NETCHAR_RESULTS_0x0840";
96 case RDP_NETCHAR_RESULTS_0x0880:
97 return "RDP_NETCHAR_RESULTS_0x0880";
98 case RDP_NETCHAR_RESULTS_0x08C0:
99 return "RDP_NETCHAR_RESULTS_0x08C0";
100 default:
101 return "UNKNOWN";
102 }
103 }
104
autodetect_send_rtt_measure_request(rdpContext * context,UINT16 sequenceNumber,UINT16 requestType)105 static BOOL autodetect_send_rtt_measure_request(rdpContext* context, UINT16 sequenceNumber,
106 UINT16 requestType)
107 {
108 wStream* s;
109 s = rdp_message_channel_pdu_init(context->rdp);
110
111 if (!s)
112 return FALSE;
113
114 WLog_VRB(AUTODETECT_TAG, "sending RTT Measure Request PDU");
115 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
116 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
117 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
118 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
119 context->rdp->autodetect->rttMeasureStartTime = GetTickCount64();
120 return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
121 }
122
autodetect_send_continuous_rtt_measure_request(rdpContext * context,UINT16 sequenceNumber)123 static BOOL autodetect_send_continuous_rtt_measure_request(rdpContext* context,
124 UINT16 sequenceNumber)
125 {
126 return autodetect_send_rtt_measure_request(context, sequenceNumber,
127 RDP_RTT_REQUEST_TYPE_CONTINUOUS);
128 }
129
autodetect_send_connecttime_rtt_measure_request(rdpContext * context,UINT16 sequenceNumber)130 BOOL autodetect_send_connecttime_rtt_measure_request(rdpContext* context, UINT16 sequenceNumber)
131 {
132 return autodetect_send_rtt_measure_request(context, sequenceNumber,
133 RDP_RTT_REQUEST_TYPE_CONNECTTIME);
134 }
135
autodetect_send_rtt_measure_response(rdpRdp * rdp,UINT16 sequenceNumber)136 static BOOL autodetect_send_rtt_measure_response(rdpRdp* rdp, UINT16 sequenceNumber)
137 {
138 wStream* s;
139 /* Send the response PDU to the server */
140 s = rdp_message_channel_pdu_init(rdp);
141
142 if (!s)
143 return FALSE;
144
145 WLog_VRB(AUTODETECT_TAG, "sending RTT Measure Response PDU");
146 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
147 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
148 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
149 Stream_Write_UINT16(s, RDP_RTT_RESPONSE_TYPE); /* responseType (1 byte) */
150 return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
151 }
152
autodetect_send_bandwidth_measure_start(rdpContext * context,UINT16 sequenceNumber,UINT16 requestType)153 static BOOL autodetect_send_bandwidth_measure_start(rdpContext* context, UINT16 sequenceNumber,
154 UINT16 requestType)
155 {
156 wStream* s;
157 s = rdp_message_channel_pdu_init(context->rdp);
158
159 if (!s)
160 return FALSE;
161
162 WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Start PDU");
163 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
164 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
165 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
166 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
167 return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
168 }
169
autodetect_send_continuous_bandwidth_measure_start(rdpContext * context,UINT16 sequenceNumber)170 static BOOL autodetect_send_continuous_bandwidth_measure_start(rdpContext* context,
171 UINT16 sequenceNumber)
172 {
173 return autodetect_send_bandwidth_measure_start(context, sequenceNumber,
174 RDP_BW_START_REQUEST_TYPE_CONTINUOUS);
175 }
176
autodetect_send_connecttime_bandwidth_measure_start(rdpContext * context,UINT16 sequenceNumber)177 BOOL autodetect_send_connecttime_bandwidth_measure_start(rdpContext* context, UINT16 sequenceNumber)
178 {
179 return autodetect_send_bandwidth_measure_start(context, sequenceNumber,
180 RDP_BW_START_REQUEST_TYPE_CONNECTTIME);
181 }
182
autodetect_send_bandwidth_measure_payload(rdpContext * context,UINT16 payloadLength,UINT16 sequenceNumber)183 BOOL autodetect_send_bandwidth_measure_payload(rdpContext* context, UINT16 payloadLength,
184 UINT16 sequenceNumber)
185 {
186 wStream* s;
187 UCHAR* buffer = NULL;
188 BOOL bResult = FALSE;
189 s = rdp_message_channel_pdu_init(context->rdp);
190
191 if (!s)
192 return FALSE;
193
194 WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "",
195 payloadLength);
196 /* 4-bytes aligned */
197 payloadLength &= ~3;
198
199 if (!Stream_EnsureRemainingCapacity(s, 8 + payloadLength))
200 {
201 Stream_Release(s);
202 return FALSE;
203 }
204
205 Stream_Write_UINT8(s, 0x08); /* headerLength (1 byte) */
206 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
207 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
208 Stream_Write_UINT16(s, RDP_BW_PAYLOAD_REQUEST_TYPE); /* requestType (2 bytes) */
209 Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
210 /* Random data (better measurement in case the line is compressed) */
211 buffer = (UCHAR*)malloc(payloadLength);
212
213 if (NULL == buffer)
214 {
215 Stream_Release(s);
216 return FALSE;
217 }
218
219 winpr_RAND(buffer, payloadLength);
220 Stream_Write(s, buffer, payloadLength);
221 bResult = rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
222 free(buffer);
223 return bResult;
224 }
225
autodetect_send_bandwidth_measure_stop(rdpContext * context,UINT16 payloadLength,UINT16 sequenceNumber,UINT16 requestType)226 static BOOL autodetect_send_bandwidth_measure_stop(rdpContext* context, UINT16 payloadLength,
227 UINT16 sequenceNumber, UINT16 requestType)
228 {
229 wStream* s;
230 UCHAR* buffer = NULL;
231 BOOL bResult = FALSE;
232 s = rdp_message_channel_pdu_init(context->rdp);
233
234 if (!s)
235 return FALSE;
236
237 WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "",
238 payloadLength);
239 /* 4-bytes aligned */
240 payloadLength &= ~3;
241 Stream_Write_UINT8(s, requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
242 ? 0x08
243 : 0x06); /* headerLength (1 byte) */
244 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
245 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
246 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
247
248 if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
249 {
250 Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
251
252 if (payloadLength > 0)
253 {
254 if (!Stream_EnsureRemainingCapacity(s, payloadLength))
255 {
256 Stream_Release(s);
257 return FALSE;
258 }
259
260 /* Random data (better measurement in case the line is compressed) */
261 buffer = malloc(payloadLength);
262
263 if (NULL == buffer)
264 {
265 Stream_Release(s);
266 return FALSE;
267 }
268
269 winpr_RAND(buffer, payloadLength);
270 Stream_Write(s, buffer, payloadLength);
271 }
272 }
273
274 bResult = rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
275 free(buffer);
276 return bResult;
277 }
278
autodetect_send_continuous_bandwidth_measure_stop(rdpContext * context,UINT16 sequenceNumber)279 static BOOL autodetect_send_continuous_bandwidth_measure_stop(rdpContext* context,
280 UINT16 sequenceNumber)
281 {
282 return autodetect_send_bandwidth_measure_stop(context, 0, sequenceNumber,
283 RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS);
284 }
285
autodetect_send_connecttime_bandwidth_measure_stop(rdpContext * context,UINT16 payloadLength,UINT16 sequenceNumber)286 BOOL autodetect_send_connecttime_bandwidth_measure_stop(rdpContext* context, UINT16 payloadLength,
287 UINT16 sequenceNumber)
288 {
289 return autodetect_send_bandwidth_measure_stop(context, payloadLength, sequenceNumber,
290 RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME);
291 }
292
autodetect_send_bandwidth_measure_results(rdpRdp * rdp,UINT16 responseType,UINT16 sequenceNumber)293 static BOOL autodetect_send_bandwidth_measure_results(rdpRdp* rdp, UINT16 responseType,
294 UINT16 sequenceNumber)
295 {
296 BOOL success = TRUE;
297 wStream* s;
298 UINT64 timeDelta;
299 /* Compute the total time */
300 timeDelta = GetTickCount64() - rdp->autodetect->bandwidthMeasureStartTime;
301 /* Send the result PDU to the server */
302 s = rdp_message_channel_pdu_init(rdp);
303
304 if (!s)
305 return FALSE;
306
307 WLog_VRB(AUTODETECT_TAG,
308 "sending Bandwidth Measure Results PDU -> timeDelta=%" PRIu32 ", byteCount=%" PRIu32
309 "",
310 timeDelta, rdp->autodetect->bandwidthMeasureByteCount);
311 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
312 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
313 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
314 Stream_Write_UINT16(s, responseType); /* responseType (1 byte) */
315 Stream_Write_UINT32(s, timeDelta); /* timeDelta (4 bytes) */
316 Stream_Write_UINT32(s, rdp->autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
317 IFCALLRET(rdp->autodetect->ClientBandwidthMeasureResult, success, rdp->context,
318 rdp->autodetect);
319
320 if (!success)
321 return FALSE;
322
323 return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
324 }
325
autodetect_send_netchar_result(rdpContext * context,UINT16 sequenceNumber)326 static BOOL autodetect_send_netchar_result(rdpContext* context, UINT16 sequenceNumber)
327 {
328 wStream* s;
329 s = rdp_message_channel_pdu_init(context->rdp);
330
331 if (!s)
332 return FALSE;
333
334 WLog_VRB(AUTODETECT_TAG, "sending Bandwidth Network Characteristics Result PDU");
335
336 if (context->rdp->autodetect->netCharBandwidth > 0)
337 {
338 Stream_Write_UINT8(s, 0x12); /* headerLength (1 byte) */
339 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
340 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
341 Stream_Write_UINT16(s, RDP_NETCHAR_RESULTS_0x08C0); /* requestType (2 bytes) */
342 Stream_Write_UINT32(s, context->rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
343 Stream_Write_UINT32(s,
344 context->rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
345 Stream_Write_UINT32(s,
346 context->rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
347 }
348 else
349 {
350 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
351 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
352 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
353 Stream_Write_UINT16(s, RDP_NETCHAR_RESULTS_0x0840); /* requestType (2 bytes) */
354 Stream_Write_UINT32(s, context->rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
355 Stream_Write_UINT32(s,
356 context->rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
357 }
358
359 return rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ);
360 }
361
autodetect_send_netchar_sync(rdpRdp * rdp,UINT16 sequenceNumber)362 static BOOL autodetect_send_netchar_sync(rdpRdp* rdp, UINT16 sequenceNumber)
363 {
364 wStream* s;
365 /* Send the response PDU to the server */
366 s = rdp_message_channel_pdu_init(rdp);
367
368 if (!s)
369 return FALSE;
370
371 WLog_VRB(AUTODETECT_TAG,
372 "sending Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32 "",
373 rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT);
374 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
375 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
376 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
377 Stream_Write_UINT16(s, RDP_NETCHAR_SYNC_RESPONSE_TYPE); /* responseType (1 byte) */
378 Stream_Write_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
379 Stream_Write_UINT32(s, rdp->autodetect->netCharAverageRTT); /* rtt (4 bytes) */
380 return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
381 }
382
autodetect_recv_rtt_measure_request(rdpRdp * rdp,wStream * s,AUTODETECT_REQ_PDU * autodetectReqPdu)383 static BOOL autodetect_recv_rtt_measure_request(rdpRdp* rdp, wStream* s,
384 AUTODETECT_REQ_PDU* autodetectReqPdu)
385 {
386 if (autodetectReqPdu->headerLength != 0x06)
387 return FALSE;
388
389 WLog_VRB(AUTODETECT_TAG, "received RTT Measure Request PDU");
390 /* Send a response to the server */
391 return autodetect_send_rtt_measure_response(rdp, autodetectReqPdu->sequenceNumber);
392 }
393
autodetect_recv_rtt_measure_response(rdpRdp * rdp,wStream * s,AUTODETECT_RSP_PDU * autodetectRspPdu)394 static BOOL autodetect_recv_rtt_measure_response(rdpRdp* rdp, wStream* s,
395 AUTODETECT_RSP_PDU* autodetectRspPdu)
396 {
397 BOOL success = TRUE;
398
399 if (autodetectRspPdu->headerLength != 0x06)
400 return FALSE;
401
402 WLog_VRB(AUTODETECT_TAG, "received RTT Measure Response PDU");
403 rdp->autodetect->netCharAverageRTT = GetTickCount64() - rdp->autodetect->rttMeasureStartTime;
404
405 if (rdp->autodetect->netCharBaseRTT == 0 ||
406 rdp->autodetect->netCharBaseRTT > rdp->autodetect->netCharAverageRTT)
407 rdp->autodetect->netCharBaseRTT = rdp->autodetect->netCharAverageRTT;
408
409 IFCALLRET(rdp->autodetect->RTTMeasureResponse, success, rdp->context,
410 autodetectRspPdu->sequenceNumber);
411 return success;
412 }
413
autodetect_recv_bandwidth_measure_start(rdpRdp * rdp,wStream * s,AUTODETECT_REQ_PDU * autodetectReqPdu)414 static BOOL autodetect_recv_bandwidth_measure_start(rdpRdp* rdp, wStream* s,
415 AUTODETECT_REQ_PDU* autodetectReqPdu)
416 {
417 if (autodetectReqPdu->headerLength != 0x06)
418 return FALSE;
419
420 WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Start PDU - time=%" PRIu64 "",
421 GetTickCount64());
422 /* Initialize bandwidth measurement parameters */
423 rdp->autodetect->bandwidthMeasureStartTime = GetTickCount64();
424 rdp->autodetect->bandwidthMeasureByteCount = 0;
425
426 /* Continuous Auto-Detection: mark the start of the measurement */
427 if (autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONTINUOUS)
428 {
429 rdp->autodetect->bandwidthMeasureStarted = TRUE;
430 }
431
432 return TRUE;
433 }
434
autodetect_recv_bandwidth_measure_payload(rdpRdp * rdp,wStream * s,AUTODETECT_REQ_PDU * autodetectReqPdu)435 static BOOL autodetect_recv_bandwidth_measure_payload(rdpRdp* rdp, wStream* s,
436 AUTODETECT_REQ_PDU* autodetectReqPdu)
437 {
438 UINT16 payloadLength;
439
440 if (autodetectReqPdu->headerLength != 0x08)
441 return FALSE;
442
443 if (Stream_GetRemainingLength(s) < 2)
444 return FALSE;
445
446 Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
447 if (!Stream_SafeSeek(s, payloadLength))
448 return FALSE;
449 WLog_DBG(AUTODETECT_TAG, "received Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "",
450 payloadLength);
451 /* Add the payload length to the bandwidth measurement parameters */
452 rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
453 return TRUE;
454 }
455
autodetect_recv_bandwidth_measure_stop(rdpRdp * rdp,wStream * s,AUTODETECT_REQ_PDU * autodetectReqPdu)456 static BOOL autodetect_recv_bandwidth_measure_stop(rdpRdp* rdp, wStream* s,
457 AUTODETECT_REQ_PDU* autodetectReqPdu)
458 {
459 UINT16 payloadLength;
460 UINT16 responseType;
461
462 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
463 {
464 if (autodetectReqPdu->headerLength != 0x08)
465 return FALSE;
466
467 if (Stream_GetRemainingLength(s) < 2)
468 return FALSE;
469
470 Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
471 }
472 else
473 {
474 if (autodetectReqPdu->headerLength != 0x06)
475 return FALSE;
476
477 payloadLength = 0;
478 }
479
480 if (!Stream_SafeSeek(s, payloadLength))
481 return FALSE;
482
483 WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "",
484 payloadLength);
485 /* Add the payload length to the bandwidth measurement parameters */
486 rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
487
488 /* Continuous Auto-Detection: mark the stop of the measurement */
489 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
490 {
491 rdp->autodetect->bandwidthMeasureStarted = FALSE;
492 }
493
494 /* Send a response the server */
495 responseType = autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
496 ? RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME
497 : RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS;
498 return autodetect_send_bandwidth_measure_results(rdp, responseType,
499 autodetectReqPdu->sequenceNumber);
500 }
501
autodetect_recv_bandwidth_measure_results(rdpRdp * rdp,wStream * s,AUTODETECT_RSP_PDU * autodetectRspPdu)502 static BOOL autodetect_recv_bandwidth_measure_results(rdpRdp* rdp, wStream* s,
503 AUTODETECT_RSP_PDU* autodetectRspPdu)
504 {
505 BOOL success = TRUE;
506
507 if (autodetectRspPdu->headerLength != 0x0E)
508 return FALSE;
509
510 WLog_VRB(AUTODETECT_TAG, "received Bandwidth Measure Results PDU");
511 if (Stream_GetRemainingLength(s) < 8)
512 return -1;
513 Stream_Read_UINT32(s, rdp->autodetect->bandwidthMeasureTimeDelta); /* timeDelta (4 bytes) */
514 Stream_Read_UINT32(s, rdp->autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
515
516 if (rdp->autodetect->bandwidthMeasureTimeDelta > 0)
517 rdp->autodetect->netCharBandwidth = rdp->autodetect->bandwidthMeasureByteCount * 8 /
518 rdp->autodetect->bandwidthMeasureTimeDelta;
519 else
520 rdp->autodetect->netCharBandwidth = 0;
521
522 IFCALLRET(rdp->autodetect->BandwidthMeasureResults, success, rdp->context,
523 autodetectRspPdu->sequenceNumber);
524 return success;
525 }
526
autodetect_recv_netchar_result(rdpRdp * rdp,wStream * s,AUTODETECT_REQ_PDU * autodetectReqPdu)527 static BOOL autodetect_recv_netchar_result(rdpRdp* rdp, wStream* s,
528 AUTODETECT_REQ_PDU* autodetectReqPdu)
529 {
530 BOOL success = TRUE;
531
532 switch (autodetectReqPdu->requestType)
533 {
534 case RDP_NETCHAR_RESULTS_0x0840:
535
536 /* baseRTT and averageRTT fields are present (bandwidth field is not) */
537 if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
538 return FALSE;
539
540 Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
541 Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
542 break;
543
544 case RDP_NETCHAR_RESULTS_0x0880:
545
546 /* bandwidth and averageRTT fields are present (baseRTT field is not) */
547 if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
548 return FALSE;
549
550 Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
551 Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
552 break;
553
554 case RDP_NETCHAR_RESULTS_0x08C0:
555
556 /* baseRTT, bandwidth, and averageRTT fields are present */
557 if ((autodetectReqPdu->headerLength != 0x12) || (Stream_GetRemainingLength(s) < 12))
558 return FALSE;
559
560 Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
561 Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
562 Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
563 break;
564 }
565
566 WLog_VRB(AUTODETECT_TAG,
567 "received Network Characteristics Result PDU -> baseRTT=%" PRIu32
568 ", bandwidth=%" PRIu32 ", averageRTT=%" PRIu32 "",
569 rdp->autodetect->netCharBaseRTT, rdp->autodetect->netCharBandwidth,
570 rdp->autodetect->netCharAverageRTT);
571 IFCALLRET(rdp->autodetect->NetworkCharacteristicsResult, success, rdp->context,
572 autodetectReqPdu->sequenceNumber);
573 return success;
574 }
575
rdp_recv_autodetect_request_packet(rdpRdp * rdp,wStream * s)576 int rdp_recv_autodetect_request_packet(rdpRdp* rdp, wStream* s)
577 {
578 AUTODETECT_REQ_PDU autodetectReqPdu;
579 BOOL success = FALSE;
580
581 if (Stream_GetRemainingLength(s) < 6)
582 return -1;
583
584 Stream_Read_UINT8(s, autodetectReqPdu.headerLength); /* headerLength (1 byte) */
585 Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId); /* headerTypeId (1 byte) */
586 Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
587 Stream_Read_UINT16(s, autodetectReqPdu.requestType); /* requestType (2 bytes) */
588 WLog_VRB(AUTODETECT_TAG,
589 "rdp_recv_autodetect_request_packet: headerLength=%" PRIu8 ", headerTypeId=%" PRIu8
590 ", sequenceNumber=%" PRIu16 ", requestType=%04" PRIx16 "",
591 autodetectReqPdu.headerLength, autodetectReqPdu.headerTypeId,
592 autodetectReqPdu.sequenceNumber, autodetectReqPdu.requestType);
593
594 if (!rdp->settings->NetworkAutoDetect)
595 {
596 WLog_WARN(AUTODETECT_TAG,
597 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request (RDP_RTT_REQUEST) [%s] "
598 "message but support was not enabled",
599 autodetect_request_type_to_string(autodetectReqPdu.requestType));
600 }
601
602 if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST)
603 {
604 WLog_ERR(AUTODETECT_TAG,
605 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request (RDP_RTT_REQUEST) [%s] "
606 "message with invalid headerTypeId=0x%04" PRIx16,
607 autodetect_request_type_to_string(autodetectReqPdu.requestType),
608 autodetectReqPdu.headerTypeId);
609 return -1;
610 }
611
612 switch (autodetectReqPdu.requestType)
613 {
614 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
615 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
616 /* RTT Measure Request (RDP_RTT_REQUEST) - MS-RDPBCGR 2.2.14.1.1 */
617 success = autodetect_recv_rtt_measure_request(rdp, s, &autodetectReqPdu);
618 break;
619
620 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
621 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
622 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
623 /* Bandwidth Measure Start (RDP_BW_START) - MS-RDPBCGR 2.2.14.1.2 */
624 success = autodetect_recv_bandwidth_measure_start(rdp, s, &autodetectReqPdu);
625 break;
626
627 case RDP_BW_PAYLOAD_REQUEST_TYPE:
628 /* Bandwidth Measure Payload (RDP_BW_PAYLOAD) - MS-RDPBCGR 2.2.14.1.3 */
629 success = autodetect_recv_bandwidth_measure_payload(rdp, s, &autodetectReqPdu);
630 break;
631
632 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
633 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
634 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
635 /* Bandwidth Measure Stop (RDP_BW_STOP) - MS-RDPBCGR 2.2.14.1.4 */
636 success = autodetect_recv_bandwidth_measure_stop(rdp, s, &autodetectReqPdu);
637 break;
638
639 case RDP_NETCHAR_RESULTS_0x0840:
640 case RDP_NETCHAR_RESULTS_0x0880:
641 case RDP_NETCHAR_RESULTS_0x08C0:
642 /* Network Characteristics Result (RDP_NETCHAR_RESULT) - MS-RDPBCGR 2.2.14.1.5 */
643 success = autodetect_recv_netchar_result(rdp, s, &autodetectReqPdu);
644 break;
645
646 default:
647 break;
648 }
649
650 return success ? 0 : -1;
651 }
652
rdp_recv_autodetect_response_packet(rdpRdp * rdp,wStream * s)653 int rdp_recv_autodetect_response_packet(rdpRdp* rdp, wStream* s)
654 {
655 AUTODETECT_RSP_PDU autodetectRspPdu;
656 BOOL success = FALSE;
657
658 if (Stream_GetRemainingLength(s) < 6)
659 return -1;
660
661 Stream_Read_UINT8(s, autodetectRspPdu.headerLength); /* headerLength (1 byte) */
662 Stream_Read_UINT8(s, autodetectRspPdu.headerTypeId); /* headerTypeId (1 byte) */
663 Stream_Read_UINT16(s, autodetectRspPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
664 Stream_Read_UINT16(s, autodetectRspPdu.responseType); /* responseType (2 bytes) */
665 WLog_VRB(AUTODETECT_TAG,
666 "rdp_recv_autodetect_response_packet: headerLength=%" PRIu8 ", headerTypeId=%" PRIu8
667 ", sequenceNumber=%" PRIu16 ", requestType=%04" PRIx16 "",
668 autodetectRspPdu.headerLength, autodetectRspPdu.headerTypeId,
669 autodetectRspPdu.sequenceNumber, autodetectRspPdu.responseType);
670
671 if (!rdp->settings->NetworkAutoDetect)
672 {
673 WLog_WARN(AUTODETECT_TAG,
674 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response (RDP_RTT_RESPONSE) [%s] "
675 "message but support was not enabled",
676 autodetect_request_type_to_string(autodetectRspPdu.responseType));
677 }
678
679 if (autodetectRspPdu.headerTypeId != TYPE_ID_AUTODETECT_RESPONSE)
680 {
681 WLog_ERR(AUTODETECT_TAG,
682 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response (RDP_RTT_RESPONSE) [%s] "
683 "message with invalid headerTypeId=0x%04" PRIx16,
684 autodetect_request_type_to_string(autodetectRspPdu.responseType),
685 autodetectRspPdu.headerTypeId);
686 return -1;
687 }
688
689 switch (autodetectRspPdu.responseType)
690 {
691 case RDP_RTT_RESPONSE_TYPE:
692 /* RTT Measure Response (RDP_RTT_RESPONSE) - MS-RDPBCGR 2.2.14.2.1 */
693 success = autodetect_recv_rtt_measure_response(rdp, s, &autodetectRspPdu);
694 break;
695
696 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
697 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
698 /* Bandwidth Measure Results (RDP_BW_RESULTS) - MS-RDPBCGR 2.2.14.2.2 */
699 success = autodetect_recv_bandwidth_measure_results(rdp, s, &autodetectRspPdu);
700 break;
701
702 default:
703 break;
704 }
705 return success ? 0 : -1;
706 }
707
autodetect_new(void)708 rdpAutoDetect* autodetect_new(void)
709 {
710 rdpAutoDetect* autoDetect = (rdpAutoDetect*)calloc(1, sizeof(rdpAutoDetect));
711
712 if (autoDetect)
713 {
714 }
715
716 return autoDetect;
717 }
718
autodetect_free(rdpAutoDetect * autoDetect)719 void autodetect_free(rdpAutoDetect* autoDetect)
720 {
721 free(autoDetect);
722 }
723
autodetect_register_server_callbacks(rdpAutoDetect * autodetect)724 void autodetect_register_server_callbacks(rdpAutoDetect* autodetect)
725 {
726 autodetect->RTTMeasureRequest = autodetect_send_continuous_rtt_measure_request;
727 autodetect->BandwidthMeasureStart = autodetect_send_continuous_bandwidth_measure_start;
728 autodetect->BandwidthMeasureStop = autodetect_send_continuous_bandwidth_measure_stop;
729 autodetect->NetworkCharacteristicsResult = autodetect_send_netchar_result;
730 }
731