Coverage Report

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