Coverage Report

Created: 2026-10-15 06:31

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