Coverage Report

Created: 2026-02-26 06:54

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