FreeRDP
Loading...
Searching...
No Matches
autodetect.c
1
20#include <freerdp/config.h>
21
22#include <winpr/crypto.h>
23#include <winpr/assert.h>
24
25#include "autodetect.h"
26#include "multitransport.h"
27
28#define TYPE_ID_AUTODETECT_REQUEST 0x00
29#define TYPE_ID_AUTODETECT_RESPONSE 0x01
30
31#define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001
32#define RDP_RTT_REQUEST_TYPE_CONNECTTIME 0x1001
33
34#define RDP_RTT_RESPONSE_TYPE 0x0000
35
36#define RDP_BW_START_REQUEST_TYPE_CONTINUOUS 0x0014
37#define RDP_BW_START_REQUEST_TYPE_TUNNEL 0x0114
38#define RDP_BW_START_REQUEST_TYPE_CONNECTTIME 0x1014
39#define RDP_BW_PAYLOAD_REQUEST_TYPE 0x0002
40#define RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME 0x002B
41#define RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS 0x0429
42#define RDP_BW_STOP_REQUEST_TYPE_TUNNEL 0x0629
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
50typedef struct
51{
52 UINT8 headerLength;
53 UINT8 headerTypeId;
54 UINT16 sequenceNumber;
55 UINT16 requestType;
56} AUTODETECT_REQ_PDU;
57
58typedef struct
59{
60 UINT8 headerLength;
61 UINT8 headerTypeId;
62 UINT16 sequenceNumber;
63 UINT16 responseType;
64} AUTODETECT_RSP_PDU;
65
66static const char* autodetect_header_type_string(UINT8 headerType, char* buffer, size_t size)
67{
68 const char* str = nullptr;
69 switch (headerType)
70 {
71 case TYPE_ID_AUTODETECT_REQUEST:
72 str = "TYPE_ID_AUTODETECT_REQUEST";
73 break;
74 case TYPE_ID_AUTODETECT_RESPONSE:
75 str = "TYPE_ID_AUTODETECT_RESPONSE";
76 break;
77 default:
78 str = "TYPE_ID_AUTODETECT_UNKNOWN";
79 break;
80 }
81
82 (void)_snprintf(buffer, size, "%s [0x%08" PRIx8 "]", str, headerType);
83 return buffer;
84}
85
86static const char* autodetect_request_type_to_string(UINT32 requestType)
87{
88 switch (requestType)
89 {
90 case RDP_RTT_RESPONSE_TYPE:
91 return "RDP_RTT_RESPONSE_TYPE";
92 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
93 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME";
94 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
95 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS";
96 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
97 return "RDP_RTT_REQUEST_TYPE_CONTINUOUS";
98 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
99 return "RDP_RTT_REQUEST_TYPE_CONNECTTIME";
100 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
101 return "RDP_BW_START_REQUEST_TYPE_CONTINUOUS";
102 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
103 return "RDP_BW_START_REQUEST_TYPE_TUNNEL";
104 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
105 return "RDP_BW_START_REQUEST_TYPE_CONNECTTIME";
106 case RDP_BW_PAYLOAD_REQUEST_TYPE:
107 return "RDP_BW_PAYLOAD_REQUEST_TYPE";
108 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
109 return "RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME";
110 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
111 return "RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS";
112 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
113 return "RDP_BW_STOP_REQUEST_TYPE_TUNNEL";
114 case RDP_NETCHAR_RESULTS_0x0840:
115 return "RDP_NETCHAR_RESULTS_0x0840";
116 case RDP_NETCHAR_RESULTS_0x0880:
117 return "RDP_NETCHAR_RESULTS_0x0880";
118 case RDP_NETCHAR_RESULTS_0x08C0:
119 return "RDP_NETCHAR_RESULTS_0x08C0";
120 default:
121 return "UNKNOWN";
122 }
123}
124
125static const char* autodetect_request_type_to_string_buffer(UINT32 requestType, char* buffer,
126 size_t size)
127{
128 const char* str = autodetect_request_type_to_string(requestType);
129 (void)_snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, requestType);
130 return buffer;
131}
132
133static BOOL autodetect_send_rtt_measure_request(rdpAutoDetect* autodetect,
134 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
135 UINT16 sequenceNumber)
136{
137 UINT16 requestType = 0;
138 UINT16 sec_flags = 0;
139 wStream* s = nullptr;
140
141 WINPR_ASSERT(autodetect);
142 WINPR_ASSERT(autodetect->context);
143
144 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
145 if (!s)
146 return FALSE;
147
148 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
149 requestType = RDP_RTT_REQUEST_TYPE_CONNECTTIME;
150 else
151 requestType = RDP_RTT_REQUEST_TYPE_CONTINUOUS;
152
153 WLog_Print(autodetect->log, WLOG_TRACE, "sending RTT Measure Request PDU");
154 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
155 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
156 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
157 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
158 autodetect->rttMeasureStartTime = GetTickCount64();
159 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
160 sec_flags | SEC_AUTODETECT_REQ);
161}
162
163static BOOL autodetect_send_rtt_measure_response(rdpAutoDetect* autodetect, UINT16 sequenceNumber)
164{
165 UINT16 sec_flags = 0;
166 wStream* s = nullptr;
167
168 WINPR_ASSERT(autodetect);
169 WINPR_ASSERT(autodetect->context);
170
171 /* Send the response PDU to the server */
172 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
173
174 if (!s)
175 return FALSE;
176
177 WLog_Print(autodetect->log, WLOG_TRACE,
178 "sending RTT Measure Response PDU (seqNumber=0x%" PRIx16 ")", sequenceNumber);
179 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
180 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
181 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
182 Stream_Write_UINT16(s, RDP_RTT_RESPONSE_TYPE); /* responseType (1 byte) */
183 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
184 sec_flags | SEC_AUTODETECT_RSP);
185}
186
187static BOOL autodetect_send_netchar_sync(rdpAutoDetect* autodetect, UINT16 sequenceNumber)
188{
189 UINT16 sec_flags = 0;
190
191 WINPR_ASSERT(autodetect);
192 WINPR_ASSERT(autodetect->context);
193
194 wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
195 if (!s)
196 return FALSE;
197
198 WLog_Print(autodetect->log, WLOG_TRACE,
199 "sending Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32,
200 autodetect->netCharBandwidth, autodetect->netCharAverageRTT);
201 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
202 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
203 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
204 Stream_Write_UINT16(s, RDP_NETCHAR_SYNC_RESPONSE_TYPE); /* responseType (2 bytes) */
205 Stream_Write_UINT32(s, autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
206 Stream_Write_UINT32(s, autodetect->netCharAverageRTT); /* rtt (4 bytes) */
207 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
208 sec_flags | SEC_AUTODETECT_RSP);
209}
210
211static BOOL autodetect_send_bandwidth_measure_start(rdpAutoDetect* autodetect,
212 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
213 UINT16 sequenceNumber)
214{
215 UINT16 requestType = 0;
216 UINT16 sec_flags = 0;
217 wStream* s = nullptr;
218
219 WINPR_ASSERT(autodetect);
220 WINPR_ASSERT(autodetect->context);
221
222 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
223 if (!s)
224 return FALSE;
225
226 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
227 requestType = RDP_BW_START_REQUEST_TYPE_CONNECTTIME;
228 else
229 requestType = RDP_BW_START_REQUEST_TYPE_CONTINUOUS;
230
231 WLog_Print(autodetect->log, WLOG_TRACE,
232 "sending Bandwidth Measure Start PDU(seqNumber=%" PRIu16 ")", sequenceNumber);
233 Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
234 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
235 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
236 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
237 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
238 sec_flags | SEC_AUTODETECT_REQ);
239}
240
241static BOOL
242autodetect_send_bandwidth_measure_payload(rdpAutoDetect* autodetect,
243 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
244 UINT16 sequenceNumber, UINT16 payloadLength)
245{
246 UINT16 sec_flags = 0;
247 wStream* s = nullptr;
248
249 WINPR_ASSERT(autodetect);
250 WINPR_ASSERT(autodetect->context);
251
252 WINPR_ASSERT(freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE);
253
254 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
255 if (!s)
256 return FALSE;
257
258 WLog_Print(autodetect->log, WLOG_TRACE,
259 "sending Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "", payloadLength);
260 /* 4-bytes aligned */
261 payloadLength &= ~3;
262
263 if (!Stream_EnsureRemainingCapacity(s, 8ull + payloadLength))
264 {
265 WLog_Print(autodetect->log, WLOG_ERROR, "Failed to ensure %lu bytes in stream",
266 8ul + payloadLength);
267 Stream_Release(s);
268 return FALSE;
269 }
270
271 Stream_Write_UINT8(s, 0x08); /* headerLength (1 byte) */
272 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
273 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
274 Stream_Write_UINT16(s, RDP_BW_PAYLOAD_REQUEST_TYPE); /* requestType (2 bytes) */
275 Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
276 /* Random data (better measurement in case the line is compressed) */
277 if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0)
278 {
279 Stream_Release(s);
280 return FALSE;
281 }
282 Stream_Seek(s, payloadLength);
283 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
284 sec_flags | SEC_AUTODETECT_REQ);
285}
286
287static BOOL autodetect_send_bandwidth_measure_stop(rdpAutoDetect* autodetect,
288 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
289 UINT16 sequenceNumber, UINT16 payloadLength)
290{
291 UINT16 requestType = 0;
292 UINT16 sec_flags = 0;
293 wStream* s = nullptr;
294
295 WINPR_ASSERT(autodetect);
296 WINPR_ASSERT(autodetect->context);
297
298 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
299 if (!s)
300 return FALSE;
301
302 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
303 requestType = RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME;
304 else
305 requestType = RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS;
306
307 if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
308 payloadLength = 0;
309
310 WLog_Print(autodetect->log, WLOG_TRACE,
311 "sending Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "", payloadLength);
312 /* 4-bytes aligned */
313 payloadLength &= ~3;
314 Stream_Write_UINT8(s, requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
315 ? 0x08
316 : 0x06); /* headerLength (1 byte) */
317 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
318 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
319 Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */
320
321 if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
322 {
323 Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
324
325 if (payloadLength > 0)
326 {
327 if (!Stream_EnsureRemainingCapacity(s, payloadLength))
328 {
329 WLog_Print(autodetect->log, WLOG_ERROR,
330 "Failed to ensure %" PRIu16 " bytes in stream", payloadLength);
331 Stream_Release(s);
332 return FALSE;
333 }
334
335 /* Random data (better measurement in case the line is compressed) */
336 if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0)
337 {
338 Stream_Release(s);
339 return FALSE;
340 }
341 Stream_Seek(s, payloadLength);
342 }
343 }
344
345 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
346 sec_flags | SEC_AUTODETECT_REQ);
347}
348
349/* [MS-RDPBCGR] 2.2.14.2.2 Bandwidth Measure Results (RDP_BW_RESULTS), 14 bytes */
350static void autodetect_write_bandwidth_measure_results(const rdpAutoDetect* autodetect, wStream* s,
351 UINT16 responseType, UINT16 sequenceNumber,
352 UINT32 timeDelta)
353{
354 WINPR_ASSERT(autodetect);
355 WINPR_ASSERT(s);
356
357 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
358 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
359 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
360 Stream_Write_UINT16(s, responseType); /* responseType (2 bytes) */
361 Stream_Write_UINT32(s, timeDelta); /* timeDelta (4 bytes) */
362 Stream_Write_UINT32(s, autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
363}
364
365static BOOL autodetect_send_bandwidth_measure_results(rdpAutoDetect* autodetect,
366 RDP_TRANSPORT_TYPE transport,
367 UINT16 responseType, UINT16 sequenceNumber)
368{
369 BOOL success = TRUE;
370 UINT16 sec_flags = 0;
371 UINT64 timeDelta = GetTickCount64();
372
373 WINPR_ASSERT(autodetect);
374 WINPR_ASSERT(autodetect->context);
375
376 /* Compute the total time */
377 if (autodetect->bandwidthMeasureStartTime > timeDelta)
378 {
379 WLog_Print(autodetect->log, WLOG_WARN,
380 "Invalid bandwidthMeasureStartTime %" PRIu64 " > current %" PRIu64
381 ", trimming to 0",
382 autodetect->bandwidthMeasureStartTime, timeDelta);
383 timeDelta = 0;
384 }
385 else
386 timeDelta -= autodetect->bandwidthMeasureStartTime;
387
388 const UINT32 delta = (UINT32)MIN(timeDelta, UINT32_MAX);
389 WLog_Print(autodetect->log, WLOG_TRACE,
390 "sending Bandwidth Measure Results PDU -> timeDelta=%" PRIu32 ", byteCount=%" PRIu32
391 "%s",
392 delta, autodetect->bandwidthMeasureByteCount,
393 (transport == RDP_TRANSPORT_UDP_R) ? " in the UDP tunnel" : "");
394
395 IFCALLRET(autodetect->ClientBandwidthMeasureResult, success, autodetect, transport,
396 responseType, sequenceNumber, delta, autodetect->bandwidthMeasureByteCount);
397 if (!success)
398 {
399 WLog_Print(autodetect->log, WLOG_ERROR, "ClientBandwidthMeasureResult failed");
400 return FALSE;
401 }
402
403 /* [MS-RDPBCGR] 3.2.5.17: a measurement stopped in a tunnel subheader is answered in one on
404 * the same tunnel ([MS-RDPEMT] 2.2.1.1.1), all others on the main channel */
405 if (transport == RDP_TRANSPORT_UDP_R)
406 {
407 BYTE buffer[0x0E] = WINPR_C_ARRAY_INIT;
408 wStream sbuffer = WINPR_C_ARRAY_INIT;
409 wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
410 autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber,
411 delta);
412 return multitransport_send_autodetect_response(autodetect->context->rdp->multitransport,
413 buffer, sizeof(buffer));
414 }
415
416 wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
417 if (!s)
418 return FALSE;
419 autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber, delta);
420 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
421 sec_flags | SEC_AUTODETECT_RSP);
422}
423
424static BOOL autodetect_send_netchar_result(rdpAutoDetect* autodetect,
425 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
426 UINT16 sequenceNumber,
427 const rdpNetworkCharacteristicsResult* result)
428{
429 UINT16 sec_flags = 0;
430 wStream* s = nullptr;
431
432 WINPR_ASSERT(autodetect);
433 WINPR_ASSERT(autodetect->context);
434
435 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
436
437 if (!s)
438 return FALSE;
439
440 WLog_Print(autodetect->log, WLOG_TRACE, "sending Network Characteristics Result PDU");
441
442 switch (result->type)
443 {
444 case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT:
445 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
446 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
447 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
448 WINPR_ASSERT((result->type <= UINT16_MAX));
449 WINPR_ASSERT((result->type >= 0));
450 Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */
451 Stream_Write_UINT32(s, result->baseRTT); /* baseRTT (4 bytes) */
452 Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */
453 break;
454 case RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT:
455 Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */
456 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
457 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
458 WINPR_ASSERT((result->type <= UINT16_MAX));
459 WINPR_ASSERT((result->type >= 0));
460 Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */
461 Stream_Write_UINT32(s, result->bandwidth); /* bandwidth (4 bytes) */
462 Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */
463 break;
464 case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT:
465 Stream_Write_UINT8(s, 0x12); /* headerLength (1 byte) */
466 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */
467 Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
468 WINPR_ASSERT((result->type <= UINT16_MAX));
469 WINPR_ASSERT((result->type >= 0));
470 Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */
471 Stream_Write_UINT32(s, result->baseRTT); /* baseRTT (4 bytes) */
472 Stream_Write_UINT32(s, result->bandwidth); /* bandwidth (4 bytes) */
473 Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */
474 break;
475 default:
476 WINPR_ASSERT(FALSE);
477 break;
478 }
479
480 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
481 sec_flags | SEC_AUTODETECT_REQ);
482}
483
484static FREERDP_AUTODETECT_STATE
485autodetect_on_connect_time_auto_detect_begin_default(rdpAutoDetect* autodetect)
486{
487 WINPR_ASSERT(autodetect);
488 WINPR_ASSERT(autodetect->RTTMeasureRequest);
489
490 if (!autodetect->RTTMeasureRequest(autodetect, RDP_TRANSPORT_TCP, 0x23))
491 return FREERDP_AUTODETECT_STATE_FAIL;
492
493 return FREERDP_AUTODETECT_STATE_REQUEST;
494}
495
496static FREERDP_AUTODETECT_STATE
497autodetect_on_connect_time_auto_detect_progress_default(rdpAutoDetect* autodetect)
498{
499 WINPR_ASSERT(autodetect);
500
501 if (autodetect->state == FREERDP_AUTODETECT_STATE_RESPONSE ||
502 autodetect->state == FREERDP_AUTODETECT_STATE_COMPLETE)
503 return FREERDP_AUTODETECT_STATE_COMPLETE;
504
505 return autodetect->state;
506}
507
508static BOOL autodetect_recv_rtt_measure_request(rdpAutoDetect* autodetect,
509 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
510 WINPR_ATTR_UNUSED wStream* s,
511 const AUTODETECT_REQ_PDU* autodetectReqPdu)
512{
513 WINPR_ASSERT(autodetect);
514 WINPR_ASSERT(s);
515 WINPR_ASSERT(autodetectReqPdu);
516
517 if (autodetectReqPdu->headerLength != 0x06)
518 {
519 WLog_Print(autodetect->log, WLOG_ERROR,
520 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]",
521 autodetectReqPdu->headerLength);
522 return FALSE;
523 }
524
525 WLog_Print(autodetect->log, WLOG_TRACE, "received RTT Measure Request PDU");
526 /* Send a response to the server */
527 return autodetect_send_rtt_measure_response(autodetect, autodetectReqPdu->sequenceNumber);
528}
529
530static BOOL autodetect_recv_rtt_measure_response(rdpAutoDetect* autodetect,
531 RDP_TRANSPORT_TYPE transport,
532 WINPR_ATTR_UNUSED wStream* s,
533 const AUTODETECT_RSP_PDU* autodetectRspPdu)
534{
535 BOOL success = TRUE;
536
537 WINPR_ASSERT(autodetect);
538 WINPR_ASSERT(autodetectRspPdu);
539
540 if (autodetectRspPdu->headerLength != 0x06)
541 {
542 WLog_Print(autodetect->log, WLOG_ERROR,
543 "autodetectRspPdu->headerLength != 0x06 [0x%02" PRIx8 "]",
544 autodetectRspPdu->headerLength);
545 return FALSE;
546 }
547
548 WLog_Print(autodetect->log, WLOG_TRACE, "received RTT Measure Response PDU");
549 autodetect->netCharAverageRTT =
550 (UINT32)MIN(GetTickCount64() - autodetect->rttMeasureStartTime, UINT32_MAX);
551
552 if (autodetect->netCharBaseRTT == 0 ||
553 autodetect->netCharBaseRTT > autodetect->netCharAverageRTT)
554 autodetect->netCharBaseRTT = autodetect->netCharAverageRTT;
555
556 IFCALLRET(autodetect->RTTMeasureResponse, success, autodetect, transport,
557 autodetectRspPdu->sequenceNumber);
558 if (!success)
559 WLog_Print(autodetect->log, WLOG_WARN, "RTTMeasureResponse failed");
560 return success;
561}
562
563static BOOL autodetect_recv_bandwidth_measure_start(rdpAutoDetect* autodetect,
564 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
565 WINPR_ATTR_UNUSED wStream* s,
566 const AUTODETECT_REQ_PDU* autodetectReqPdu)
567{
568 WINPR_ASSERT(autodetect);
569 WINPR_ASSERT(s);
570 WINPR_ASSERT(autodetectReqPdu);
571
572 if (autodetectReqPdu->headerLength != 0x06)
573 {
574 WLog_Print(autodetect->log, WLOG_ERROR,
575 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]",
576 autodetectReqPdu->headerLength);
577 return FALSE;
578 }
579
580 WLog_Print(autodetect->log, WLOG_TRACE,
581 "received Bandwidth Measure Start PDU - time=%" PRIu64 "", GetTickCount64());
582 /* Initialize bandwidth measurement parameters */
583 autodetect->bandwidthMeasureStartTime = GetTickCount64();
584 autodetect->bandwidthMeasureByteCount = 0;
585
586 /* [MS-RDPBCGR] 3.2.5.17: an auto-reconnect can answer the connect-time measurement with
587 * the bandwidth and RTT the server reported before, which ends the measurement
588 * ([MS-RDPBCGR] 2.2.14.2.3). */
589 if ((autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONNECTTIME) &&
590 (autodetect->netCharBandwidth > 0))
591 {
593 autodetect->context->settings, FreeRDP_ServerAutoReconnectCookie);
594 if (cookie && (cookie->cbLen > 0))
595 return autodetect_send_netchar_sync(autodetect, autodetectReqPdu->sequenceNumber);
596 }
597
598 /* Continuous Auto-Detection: mark the start of the measurement */
599 if (autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONTINUOUS)
600 {
601 autodetect->bandwidthMeasureStarted = TRUE;
602 }
603
604 return TRUE;
605}
606
607static BOOL
608autodetect_recv_bandwidth_measure_payload(rdpAutoDetect* autodetect,
609 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
610 wStream* s, const AUTODETECT_REQ_PDU* autodetectReqPdu)
611{
612 UINT16 payloadLength = 0;
613
614 WINPR_ASSERT(autodetect);
615 WINPR_ASSERT(s);
616 WINPR_ASSERT(autodetectReqPdu);
617
618 if (autodetectReqPdu->headerLength != 0x08)
619 {
620 WLog_Print(autodetect->log, WLOG_ERROR,
621 "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8 "]",
622 autodetectReqPdu->headerLength);
623 return FALSE;
624 }
625
626 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2))
627 return FALSE;
628
629 Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
630 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength))
631 return FALSE;
632 Stream_Seek(s, payloadLength);
633
634 WLog_Print(autodetect->log, WLOG_DEBUG,
635 "received Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "",
636 payloadLength);
637 /* Add the message to the bandwidth measurement parameters: Windows counts the whole
638 * Bandwidth Measure Payload message, header included (mstsc reports 4000 bytes for a
639 * 3992 byte payload), and ends the connect-time detection with a 5 s delay otherwise */
640 autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength;
641 autodetect->bandwidthMeasureByteCount += payloadLength;
642 return TRUE;
643}
644
645static BOOL autodetect_recv_bandwidth_measure_stop(rdpAutoDetect* autodetect,
646 RDP_TRANSPORT_TYPE transport, wStream* s,
647 const AUTODETECT_REQ_PDU* autodetectReqPdu)
648{
649 UINT16 payloadLength = 0;
650 UINT16 responseType = 0;
651
652 WINPR_ASSERT(autodetect);
653 WINPR_ASSERT(s);
654 WINPR_ASSERT(autodetectReqPdu);
655
656 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
657 {
658 if (autodetectReqPdu->headerLength != 0x08)
659 {
660 WLog_Print(autodetect->log, WLOG_ERROR,
661 "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8 "]",
662 autodetectReqPdu->headerLength);
663 return FALSE;
664 }
665
666 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2))
667 return FALSE;
668
669 Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
670 }
671 else
672 {
673 if (autodetectReqPdu->headerLength != 0x06)
674 {
675 WLog_Print(autodetect->log, WLOG_ERROR,
676 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]",
677 autodetectReqPdu->headerLength);
678 return FALSE;
679 }
680
681 payloadLength = 0;
682 }
683
684 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength))
685 return FALSE;
686 Stream_Seek(s, payloadLength);
687
688 WLog_Print(autodetect->log, WLOG_TRACE,
689 "received Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "", payloadLength);
690 /* Add the payload to the bandwidth measurement parameters, with its header as for a
691 * Bandwidth Measure Payload message (see autodetect_recv_bandwidth_measure_payload) */
692 if (payloadLength > 0)
693 {
694 autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength;
695 autodetect->bandwidthMeasureByteCount += payloadLength;
696 }
697
698 /* Continuous Auto-Detection: mark the stop of the measurement */
699 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
700 {
701 autodetect->bandwidthMeasureStarted = FALSE;
702 }
703
704 /* Send a response the server */
705 responseType = autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
706 ? RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME
707 : RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS;
708 return autodetect_send_bandwidth_measure_results(autodetect, transport, responseType,
709 autodetectReqPdu->sequenceNumber);
710}
711
712static BOOL autodetect_recv_bandwidth_measure_results(rdpAutoDetect* autodetect,
713 RDP_TRANSPORT_TYPE transport, wStream* s,
714 const AUTODETECT_RSP_PDU* autodetectRspPdu)
715{
716 UINT32 timeDelta = 0;
717 UINT32 byteCount = 0;
718 BOOL success = TRUE;
719
720 WINPR_ASSERT(autodetect);
721 WINPR_ASSERT(s);
722 WINPR_ASSERT(autodetectRspPdu);
723
724 if (autodetectRspPdu->headerLength != 0x0E)
725 {
726 WLog_Print(autodetect->log, WLOG_ERROR,
727 "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8 "]",
728 autodetectRspPdu->headerLength);
729 return FALSE;
730 }
731
732 WLog_Print(autodetect->log, WLOG_TRACE, "received Bandwidth Measure Results PDU");
733 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
734 return FALSE;
735 Stream_Read_UINT32(s, timeDelta); /* timeDelta (4 bytes) */
736 Stream_Read_UINT32(s, byteCount); /* byteCount (4 bytes) */
737
738 IFCALLRET(autodetect->BandwidthMeasureResults, success, autodetect, transport,
739 autodetectRspPdu->sequenceNumber, autodetectRspPdu->responseType, timeDelta,
740 byteCount);
741 if (!success)
742 WLog_Print(autodetect->log, WLOG_WARN, "BandwidthMeasureResults failed");
743 return success;
744}
745
746static BOOL autodetect_recv_netchar_sync(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
747 wStream* s, const AUTODETECT_RSP_PDU* autodetectRspPdu)
748{
749 UINT32 bandwidth = 0;
750 UINT32 rtt = 0;
751 BOOL success = TRUE;
752
753 WINPR_ASSERT(autodetect);
754 WINPR_ASSERT(s);
755 WINPR_ASSERT(autodetectRspPdu);
756
757 if (autodetectRspPdu->headerLength != 0x0E)
758 {
759 WLog_Print(autodetect->log, WLOG_ERROR,
760 "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8 "]",
761 autodetectRspPdu->headerLength);
762 return FALSE;
763 }
764 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
765 return FALSE;
766
767 /* bandwidth and averageRTT fields are present (baseRTT field is not) */
768 Stream_Read_UINT32(s, bandwidth); /* bandwidth (4 bytes) */
769 Stream_Read_UINT32(s, rtt); /* rtt (4 bytes) */
770
771 WLog_Print(autodetect->log, WLOG_TRACE,
772 "received Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32
773 "",
774 bandwidth, rtt);
775
776 IFCALLRET(autodetect->NetworkCharacteristicsSync, success, autodetect, transport,
777 autodetectRspPdu->sequenceNumber, bandwidth, rtt);
778 if (!success)
779 WLog_Print(autodetect->log, WLOG_WARN, "NetworkCharacteristicsSync failed");
780 return success;
781}
782
783static BOOL autodetect_recv_netchar_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
784 wStream* s, const AUTODETECT_REQ_PDU* autodetectReqPdu)
785{
786 rdpNetworkCharacteristicsResult result = {
787 .type = RDP_NETCHAR_RESERVED, .baseRTT = 0, .averageRTT = 0, .bandwidth = 0
788 };
789 BOOL success = TRUE;
790
791 WINPR_ASSERT(autodetect);
792 WINPR_ASSERT(s);
793 WINPR_ASSERT(autodetectReqPdu);
794
795 switch (autodetectReqPdu->requestType)
796 {
797 case RDP_NETCHAR_RESULTS_0x0840:
798
799 /* baseRTT and averageRTT fields are present (bandwidth field is not) */
800 if (autodetectReqPdu->headerLength != 0x0E)
801 {
802 WLog_Print(autodetect->log, WLOG_ERROR,
803 "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8 "]",
804 autodetectReqPdu->headerLength);
805 return FALSE;
806 }
807 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
808 return FALSE;
809
810 result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT;
811 Stream_Read_UINT32(s, result.baseRTT); /* baseRTT (4 bytes) */
812 Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */
813 autodetect->netCharBaseRTT = result.baseRTT;
814 break;
815
816 case RDP_NETCHAR_RESULTS_0x0880:
817
818 /* bandwidth and averageRTT fields are present (baseRTT field is not) */
819 if (autodetectReqPdu->headerLength != 0x0E)
820 {
821 WLog_Print(autodetect->log, WLOG_ERROR,
822 "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8 "]",
823 autodetectReqPdu->headerLength);
824 return FALSE;
825 }
826 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
827 return FALSE;
828
829 result.type = RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT;
830 Stream_Read_UINT32(s, result.bandwidth); /* bandwidth (4 bytes) */
831 Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */
832 autodetect->netCharBandwidth = result.bandwidth;
833 break;
834
835 case RDP_NETCHAR_RESULTS_0x08C0:
836
837 /* baseRTT, bandwidth, and averageRTT fields are present */
838 if (autodetectReqPdu->headerLength != 0x12)
839 {
840 WLog_Print(autodetect->log, WLOG_ERROR,
841 "autodetectReqPdu->headerLength != 0x012 [0x%02" PRIx8 "]",
842 autodetectReqPdu->headerLength);
843 return FALSE;
844 }
845 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 12))
846 return FALSE;
847
848 result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT;
849 Stream_Read_UINT32(s, result.baseRTT); /* baseRTT (4 bytes) */
850 Stream_Read_UINT32(s, result.bandwidth); /* bandwidth (4 bytes) */
851 Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */
852 autodetect->netCharBaseRTT = result.baseRTT;
853 autodetect->netCharBandwidth = result.bandwidth;
854 break;
855
856 default:
857 WINPR_ASSERT(FALSE);
858 break;
859 }
860 /* [MS-RDPBCGR] 3.2.5.17: the metrics are kept for a Network Characteristics Sync */
861 autodetect->netCharAverageRTT = result.averageRTT;
862
863 WLog_Print(autodetect->log, WLOG_TRACE,
864 "received Network Characteristics Result PDU -> baseRTT=%" PRIu32
865 ", bandwidth=%" PRIu32 ", averageRTT=%" PRIu32 "",
866 result.baseRTT, result.bandwidth, result.averageRTT);
867
868 IFCALLRET(autodetect->NetworkCharacteristicsResult, success, autodetect, transport,
869 autodetectReqPdu->sequenceNumber, &result);
870 if (!success)
871 WLog_Print(autodetect->log, WLOG_WARN, "NetworkCharacteristicsResult failed");
872 return success;
873}
874
875state_run_t autodetect_recv_request_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
876 wStream* s)
877{
878 AUTODETECT_REQ_PDU autodetectReqPdu = WINPR_C_ARRAY_INIT;
879 const rdpSettings* settings = nullptr;
880 BOOL success = FALSE;
881
882 WINPR_ASSERT(autodetect);
883 WINPR_ASSERT(autodetect->context);
884
885 settings = autodetect->context->settings;
886 WINPR_ASSERT(settings);
887
888 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6))
889 return STATE_RUN_FAILED;
890
891 Stream_Read_UINT8(s, autodetectReqPdu.headerLength); /* headerLength (1 byte) */
892 Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId); /* headerTypeId (1 byte) */
893 Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
894 Stream_Read_UINT16(s, autodetectReqPdu.requestType); /* requestType (2 bytes) */
895
896 if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE))
897 {
898 char rbuffer[128] = WINPR_C_ARRAY_INIT;
899 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
900 autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer));
901
902 char hbuffer[128] = WINPR_C_ARRAY_INIT;
903 const char* headerStr =
904 autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer, sizeof(hbuffer));
905
906 WLog_Print(autodetect->log, WLOG_TRACE,
907 "rdp_recv_autodetect_request_packet: headerLength=%" PRIu8
908 ", headerTypeId=%s, sequenceNumber=%" PRIu16 ", requestType=%s",
909 autodetectReqPdu.headerLength, headerStr, autodetectReqPdu.sequenceNumber,
910 requestTypeStr);
911 }
912
913 if (!freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
914 {
915 char rbuffer[128] = WINPR_C_ARRAY_INIT;
916 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
917 autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer));
918
919 WLog_Print(autodetect->log, WLOG_WARN,
920 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] "
921 "message but support was not enabled",
922 requestTypeStr);
923 goto fail;
924 }
925
926 if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST)
927 {
928 char rbuffer[128] = WINPR_C_ARRAY_INIT;
929 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
930 autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer));
931 char hbuffer[128] = WINPR_C_ARRAY_INIT;
932 const char* headerStr =
933 autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer, sizeof(hbuffer));
934
935 WLog_Print(autodetect->log, WLOG_ERROR,
936 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] "
937 "message with invalid headerTypeId=%s",
938 requestTypeStr, headerStr);
939 goto fail;
940 }
941
942 if (!IFCALLRESULT(TRUE, autodetect->RequestReceived, autodetect, transport,
943 autodetectReqPdu.requestType, autodetectReqPdu.sequenceNumber))
944 goto fail;
945
946 switch (autodetectReqPdu.requestType)
947 {
948 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
949 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
950 /* RTT Measure Request (RDP_RTT_REQUEST) - MS-RDPBCGR 2.2.14.1.1 */
951 success =
952 autodetect_recv_rtt_measure_request(autodetect, transport, s, &autodetectReqPdu);
953 break;
954
955 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
956 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
957 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
958 /* Bandwidth Measure Start (RDP_BW_START) - MS-RDPBCGR 2.2.14.1.2 */
959 success = autodetect_recv_bandwidth_measure_start(autodetect, transport, s,
960 &autodetectReqPdu);
961 break;
962
963 case RDP_BW_PAYLOAD_REQUEST_TYPE:
964 /* Bandwidth Measure Payload (RDP_BW_PAYLOAD) - MS-RDPBCGR 2.2.14.1.3 */
965 success = autodetect_recv_bandwidth_measure_payload(autodetect, transport, s,
966 &autodetectReqPdu);
967 break;
968
969 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
970 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
971 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
972 /* Bandwidth Measure Stop (RDP_BW_STOP) - MS-RDPBCGR 2.2.14.1.4 */
973 success =
974 autodetect_recv_bandwidth_measure_stop(autodetect, transport, s, &autodetectReqPdu);
975 break;
976
977 case RDP_NETCHAR_RESULTS_0x0840:
978 case RDP_NETCHAR_RESULTS_0x0880:
979 case RDP_NETCHAR_RESULTS_0x08C0:
980 /* Network Characteristics Result (RDP_NETCHAR_RESULT) - MS-RDPBCGR 2.2.14.1.5 */
981 success = autodetect_recv_netchar_request(autodetect, transport, s, &autodetectReqPdu);
982 break;
983
984 default:
985 WLog_Print(autodetect->log, WLOG_ERROR, "Unknown requestType=0x%04" PRIx16,
986 autodetectReqPdu.requestType);
987 break;
988 }
989
990fail:
991 if (success)
992 autodetect->state = FREERDP_AUTODETECT_STATE_REQUEST;
993 else
994 autodetect->state = FREERDP_AUTODETECT_STATE_FAIL;
995 return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED;
996}
997
998state_run_t autodetect_recv_tunnel_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
999 wStream* s)
1000{
1001 WINPR_ASSERT(autodetect);
1002 WINPR_ASSERT(s);
1003
1004 /* [MS-RDPBCGR] 1.3.9: Continuous Auto-Detection over a sideband channel sends Bandwidth
1005 * Measure Start, Bandwidth Measure Stop and Network Characteristics Result. The result needs
1006 * no answer, a Stop on the reliable tunnel is answered on it ([MS-RDPBCGR] 3.2.5.17). Start
1007 * and Stop of a lossy tunnel (0x0114, 0x0629) are not, there is none. */
1008 UINT16 requestType = 0;
1009 if (Stream_GetRemainingLength(s) >= 6)
1010 {
1011 const BYTE* header = Stream_ConstPointer(s);
1012 requestType = winpr_Data_Get_UINT16(&header[4]);
1013 }
1014
1015 switch (requestType)
1016 {
1017 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
1018 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
1019 case RDP_NETCHAR_RESULTS_0x0840:
1020 case RDP_NETCHAR_RESULTS_0x0880:
1021 case RDP_NETCHAR_RESULTS_0x08C0:
1022 return autodetect_recv_request_packet(autodetect, transport, s);
1023
1024 default:
1025 WLog_Print(autodetect->log, WLOG_DEBUG,
1026 "ignoring auto-detect request 0x%04" PRIx16 " in a tunnel subheader",
1027 requestType);
1028 return STATE_RUN_SUCCESS;
1029 }
1030}
1031
1032state_run_t autodetect_recv_response_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
1033 wStream* s)
1034{
1035 AUTODETECT_RSP_PDU autodetectRspPdu = WINPR_C_ARRAY_INIT;
1036 const rdpSettings* settings = nullptr;
1037 BOOL success = FALSE;
1038
1039 WINPR_ASSERT(autodetect);
1040 WINPR_ASSERT(autodetect->context);
1041 WINPR_ASSERT(s);
1042
1043 settings = autodetect->context->settings;
1044 WINPR_ASSERT(settings);
1045
1046 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6))
1047 goto fail;
1048
1049 Stream_Read_UINT8(s, autodetectRspPdu.headerLength); /* headerLength (1 byte) */
1050 Stream_Read_UINT8(s, autodetectRspPdu.headerTypeId); /* headerTypeId (1 byte) */
1051 Stream_Read_UINT16(s, autodetectRspPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
1052 Stream_Read_UINT16(s, autodetectRspPdu.responseType); /* responseType (2 bytes) */
1053
1054 if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE))
1055 {
1056 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1057 const char* requestStr = autodetect_request_type_to_string_buffer(
1058 autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer));
1059 char hbuffer[128] = WINPR_C_ARRAY_INIT;
1060 const char* headerStr =
1061 autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer, sizeof(hbuffer));
1062
1063 WLog_Print(autodetect->log, WLOG_TRACE,
1064 "rdp_recv_autodetect_response_packet: headerLength=%" PRIu8 ", headerTypeId=%s"
1065 ", sequenceNumber=%" PRIu16 ", requestType=%s",
1066 autodetectRspPdu.headerLength, headerStr, autodetectRspPdu.sequenceNumber,
1067 requestStr);
1068 }
1069
1070 if (!freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
1071 {
1072 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1073
1074 const char* requestStr = autodetect_request_type_to_string_buffer(
1075 autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer));
1076
1077 WLog_Print(autodetect->log, WLOG_WARN,
1078 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] "
1079 "message but support was not enabled",
1080 requestStr);
1081 return STATE_RUN_FAILED;
1082 }
1083
1084 if (autodetectRspPdu.headerTypeId != TYPE_ID_AUTODETECT_RESPONSE)
1085 {
1086 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1087 const char* requestStr = autodetect_request_type_to_string_buffer(
1088 autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer));
1089 char hbuffer[128] = WINPR_C_ARRAY_INIT;
1090 const char* headerStr =
1091 autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer, sizeof(hbuffer));
1092 WLog_Print(autodetect->log, WLOG_ERROR,
1093 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] "
1094 "message with invalid headerTypeId=%s",
1095 requestStr, headerStr);
1096 goto fail;
1097 }
1098
1099 if (!IFCALLRESULT(TRUE, autodetect->ResponseReceived, autodetect, transport,
1100 autodetectRspPdu.responseType, autodetectRspPdu.sequenceNumber))
1101 goto fail;
1102
1103 switch (autodetectRspPdu.responseType)
1104 {
1105 case RDP_RTT_RESPONSE_TYPE:
1106 /* RTT Measure Response (RDP_RTT_RESPONSE) - MS-RDPBCGR 2.2.14.2.1 */
1107 success =
1108 autodetect_recv_rtt_measure_response(autodetect, transport, s, &autodetectRspPdu);
1109 break;
1110
1111 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
1112 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
1113 /* Bandwidth Measure Results (RDP_BW_RESULTS) - MS-RDPBCGR 2.2.14.2.2 */
1114 success = autodetect_recv_bandwidth_measure_results(autodetect, transport, s,
1115 &autodetectRspPdu);
1116 break;
1117
1118 case RDP_NETCHAR_SYNC_RESPONSE_TYPE:
1119 /* Network Characteristics Sync (RDP_NETCHAR_SYNC) - MS-RDPBCGR 2.2.14.2.3 */
1120 success = autodetect_recv_netchar_sync(autodetect, transport, s, &autodetectRspPdu);
1121 break;
1122
1123 default:
1124 WLog_Print(autodetect->log, WLOG_ERROR, "Unknown responseType=0x%04" PRIx16,
1125 autodetectRspPdu.responseType);
1126 break;
1127 }
1128
1129fail:
1130 if (success)
1131 {
1132 if (autodetectRspPdu.responseType == RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME)
1133 autodetect->state = FREERDP_AUTODETECT_STATE_COMPLETE;
1134 else
1135 autodetect->state = FREERDP_AUTODETECT_STATE_RESPONSE;
1136 }
1137 else
1138 autodetect->state = FREERDP_AUTODETECT_STATE_FAIL;
1139
1140 return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED;
1141}
1142
1143void autodetect_on_connect_time_auto_detect_begin(rdpAutoDetect* autodetect)
1144{
1145 WINPR_ASSERT(autodetect);
1146 WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectBegin);
1147
1148 autodetect->state = autodetect->OnConnectTimeAutoDetectBegin(autodetect);
1149}
1150
1151void autodetect_on_connect_time_auto_detect_progress(rdpAutoDetect* autodetect)
1152{
1153 WINPR_ASSERT(autodetect);
1154 WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectProgress);
1155
1156 autodetect->state = autodetect->OnConnectTimeAutoDetectProgress(autodetect);
1157}
1158
1159rdpAutoDetect* autodetect_new(rdpContext* context)
1160{
1161 rdpAutoDetect* autoDetect = (rdpAutoDetect*)calloc(1, sizeof(rdpAutoDetect));
1162 if (!autoDetect)
1163 return nullptr;
1164 autoDetect->context = context;
1165 autoDetect->log = WLog_Get(AUTODETECT_TAG);
1166
1167 return autoDetect;
1168}
1169
1170void autodetect_free(rdpAutoDetect* autoDetect)
1171{
1172 free(autoDetect);
1173}
1174
1175void autodetect_register_server_callbacks(rdpAutoDetect* autodetect)
1176{
1177 WINPR_ASSERT(autodetect);
1178
1179 autodetect->RTTMeasureRequest = autodetect_send_rtt_measure_request;
1180 autodetect->BandwidthMeasureStart = autodetect_send_bandwidth_measure_start;
1181 autodetect->BandwidthMeasurePayload = autodetect_send_bandwidth_measure_payload;
1182 autodetect->BandwidthMeasureStop = autodetect_send_bandwidth_measure_stop;
1183 autodetect->NetworkCharacteristicsResult = autodetect_send_netchar_result;
1184
1185 /*
1186 * Default handlers for Connect-Time Auto-Detection
1187 * (MAY be overridden by the API user)
1188 */
1189 autodetect->OnConnectTimeAutoDetectBegin = autodetect_on_connect_time_auto_detect_begin_default;
1190 autodetect->OnConnectTimeAutoDetectProgress =
1191 autodetect_on_connect_time_auto_detect_progress_default;
1192}
1193
1194FREERDP_AUTODETECT_STATE autodetect_get_state(rdpAutoDetect* autodetect)
1195{
1196 WINPR_ASSERT(autodetect);
1197 return autodetect->state;
1198}
1199
1200rdpAutoDetect* autodetect_get(rdpContext* context)
1201{
1202 WINPR_ASSERT(context);
1203 WINPR_ASSERT(context->rdp);
1204 return context->rdp->autodetect;
1205}
WINPR_ATTR_NODISCARD FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.