Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/comm/comm_ioctl.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Serial Communication API
4
 *
5
 * Copyright 2011 O.S. Systems Software Ltda.
6
 * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
7
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
8
 * Copyright 2014 Hewlett-Packard Development Company, L.P.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 *     http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22
23
#include <winpr/config.h>
24
25
#if defined __linux__ && !defined ANDROID
26
27
#include <winpr/assert.h>
28
#include <errno.h>
29
30
#include <winpr/wlog.h>
31
32
#include "comm.h"
33
#include "comm_ioctl.h"
34
#include "comm_serial_sys.h"
35
#include "comm_sercx_sys.h"
36
#include "comm_sercx2_sys.h"
37
38
/* NB: MS-RDPESP's recommendation:
39
 *
40
 * <2> Section 3.2.5.1.6: Windows Implementations use IOCTL constants
41
 * for IoControlCode values.  The content and values of the IOCTLs are
42
 * opaque to the protocol. On the server side, the data contained in
43
 * an IOCTL is simply packaged and sent to the client side. For
44
 * maximum compatibility between the different versions of the Windows
45
 * operating system, the client implementation only singles out
46
 * critical IOCTLs and invokes the applicable Win32 port API. The
47
 * other IOCTLS are passed directly to the client-side driver, and the
48
 * processing of this value depends on the drivers installed on the
49
 * client side. The values and parameters for these IOCTLS can be
50
 * found in [MSFT-W2KDDK] Volume 2, Part 2—Serial and Parallel
51
 * Drivers, and in [MSDN-PORTS].
52
 */
53
54
const char* _comm_serial_ioctl_name(ULONG number)
55
0
{
56
0
  for (int i = 0; _SERIAL_IOCTL_NAMES[i].number != 0; i++)
57
0
  {
58
0
    if (_SERIAL_IOCTL_NAMES[i].number == number)
59
0
    {
60
0
      return _SERIAL_IOCTL_NAMES[i].name;
61
0
    }
62
0
  }
63
64
0
  return "(unknown ioctl name)";
65
0
}
66
67
static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
68
                                  DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
69
                                  LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
70
0
{
71
0
  WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
72
0
  SERIAL_DRIVER* pServerSerialDriver = NULL;
73
74
0
  if (!CommIsHandleValid(hDevice))
75
0
    return FALSE;
76
77
0
  if (lpOverlapped)
78
0
  {
79
0
    SetLastError(ERROR_NOT_SUPPORTED);
80
0
    return FALSE;
81
0
  }
82
83
0
  if (lpBytesReturned == NULL)
84
0
  {
85
0
    SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */
86
0
    return FALSE;
87
0
  }
88
89
  /* clear any previous last error */
90
0
  SetLastError(ERROR_SUCCESS);
91
92
0
  *lpBytesReturned = 0; /* will be ajusted if required ... */
93
94
0
  CommLog_Print(WLOG_DEBUG, "CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode);
95
96
  /* remoteSerialDriver to be use ...
97
   *
98
   * FIXME: might prefer to use an automatic rather than static structure
99
   */
100
0
  switch (pComm->serverSerialDriverId)
101
0
  {
102
0
    case SerialDriverSerialSys:
103
0
      pServerSerialDriver = SerialSys_s();
104
0
      break;
105
106
0
    case SerialDriverSerCxSys:
107
0
      pServerSerialDriver = SerCxSys_s();
108
0
      break;
109
110
0
    case SerialDriverSerCx2Sys:
111
0
      pServerSerialDriver = SerCx2Sys_s();
112
0
      break;
113
114
0
    case SerialDriverUnknown:
115
0
    default:
116
0
      CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%d), using SerCx2.sys",
117
0
                    pComm->serverSerialDriverId);
118
0
      pServerSerialDriver = SerCx2Sys_s();
119
0
      break;
120
0
  }
121
122
0
  WINPR_ASSERT(pServerSerialDriver != NULL);
123
124
0
  switch (dwIoControlCode)
125
0
  {
126
0
    case IOCTL_USBPRINT_GET_1284_ID:
127
0
    {
128
      /* FIXME:
129
       * http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */
130
0
      *lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */
131
0
      SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
132
0
      return FALSE;
133
0
    }
134
0
    case IOCTL_SERIAL_SET_BAUD_RATE:
135
0
    {
136
0
      if (pServerSerialDriver->set_baud_rate)
137
0
      {
138
0
        SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer;
139
140
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_BAUD_RATE));
141
0
        if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
142
0
        {
143
0
          SetLastError(ERROR_INVALID_PARAMETER);
144
0
          return FALSE;
145
0
        }
146
147
0
        return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
148
0
      }
149
0
      break;
150
0
    }
151
0
    case IOCTL_SERIAL_GET_BAUD_RATE:
152
0
    {
153
0
      if (pServerSerialDriver->get_baud_rate)
154
0
      {
155
0
        SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer;
156
157
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE));
158
0
        if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE))
159
0
        {
160
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
161
0
          return FALSE;
162
0
        }
163
164
0
        if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
165
0
          return FALSE;
166
167
0
        *lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
168
0
        return TRUE;
169
0
      }
170
0
      break;
171
0
    }
172
0
    case IOCTL_SERIAL_GET_PROPERTIES:
173
0
    {
174
0
      if (pServerSerialDriver->get_properties)
175
0
      {
176
0
        COMMPROP* pProperties = (COMMPROP*)lpOutBuffer;
177
178
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(COMMPROP));
179
0
        if (nOutBufferSize < sizeof(COMMPROP))
180
0
        {
181
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
182
0
          return FALSE;
183
0
        }
184
185
0
        if (!pServerSerialDriver->get_properties(pComm, pProperties))
186
0
          return FALSE;
187
188
0
        *lpBytesReturned = sizeof(COMMPROP);
189
0
        return TRUE;
190
0
      }
191
0
      break;
192
0
    }
193
0
    case IOCTL_SERIAL_SET_CHARS:
194
0
    {
195
0
      if (pServerSerialDriver->set_serial_chars)
196
0
      {
197
0
        SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpInBuffer;
198
199
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_CHARS));
200
0
        if (nInBufferSize < sizeof(SERIAL_CHARS))
201
0
        {
202
0
          SetLastError(ERROR_INVALID_PARAMETER);
203
0
          return FALSE;
204
0
        }
205
206
0
        return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
207
0
      }
208
0
      break;
209
0
    }
210
0
    case IOCTL_SERIAL_GET_CHARS:
211
0
    {
212
0
      if (pServerSerialDriver->get_serial_chars)
213
0
      {
214
0
        SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpOutBuffer;
215
216
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_CHARS));
217
0
        if (nOutBufferSize < sizeof(SERIAL_CHARS))
218
0
        {
219
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
220
0
          return FALSE;
221
0
        }
222
223
0
        if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
224
0
          return FALSE;
225
226
0
        *lpBytesReturned = sizeof(SERIAL_CHARS);
227
0
        return TRUE;
228
0
      }
229
0
      break;
230
0
    }
231
0
    case IOCTL_SERIAL_SET_LINE_CONTROL:
232
0
    {
233
0
      if (pServerSerialDriver->set_line_control)
234
0
      {
235
0
        SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer;
236
237
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL));
238
0
        if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL))
239
0
        {
240
0
          SetLastError(ERROR_INVALID_PARAMETER);
241
0
          return FALSE;
242
0
        }
243
244
0
        return pServerSerialDriver->set_line_control(pComm, pLineControl);
245
0
      }
246
0
      break;
247
0
    }
248
0
    case IOCTL_SERIAL_GET_LINE_CONTROL:
249
0
    {
250
0
      if (pServerSerialDriver->get_line_control)
251
0
      {
252
0
        SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer;
253
254
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL));
255
0
        if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL))
256
0
        {
257
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
258
0
          return FALSE;
259
0
        }
260
261
0
        if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
262
0
          return FALSE;
263
264
0
        *lpBytesReturned = sizeof(SERIAL_LINE_CONTROL);
265
0
        return TRUE;
266
0
      }
267
0
      break;
268
0
    }
269
0
    case IOCTL_SERIAL_SET_HANDFLOW:
270
0
    {
271
0
      if (pServerSerialDriver->set_handflow)
272
0
      {
273
0
        SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpInBuffer;
274
275
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_HANDFLOW));
276
0
        if (nInBufferSize < sizeof(SERIAL_HANDFLOW))
277
0
        {
278
0
          SetLastError(ERROR_INVALID_PARAMETER);
279
0
          return FALSE;
280
0
        }
281
282
0
        return pServerSerialDriver->set_handflow(pComm, pHandflow);
283
0
      }
284
0
      break;
285
0
    }
286
0
    case IOCTL_SERIAL_GET_HANDFLOW:
287
0
    {
288
0
      if (pServerSerialDriver->get_handflow)
289
0
      {
290
0
        SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer;
291
292
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_HANDFLOW));
293
0
        if (nOutBufferSize < sizeof(SERIAL_HANDFLOW))
294
0
        {
295
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
296
0
          return FALSE;
297
0
        }
298
299
0
        if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
300
0
          return FALSE;
301
302
0
        *lpBytesReturned = sizeof(SERIAL_HANDFLOW);
303
0
        return TRUE;
304
0
      }
305
0
      break;
306
0
    }
307
0
    case IOCTL_SERIAL_SET_TIMEOUTS:
308
0
    {
309
0
      if (pServerSerialDriver->set_timeouts)
310
0
      {
311
0
        SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer;
312
313
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_TIMEOUTS));
314
0
        if (nInBufferSize < sizeof(SERIAL_TIMEOUTS))
315
0
        {
316
0
          SetLastError(ERROR_INVALID_PARAMETER);
317
0
          return FALSE;
318
0
        }
319
320
0
        return pServerSerialDriver->set_timeouts(pComm, pHandflow);
321
0
      }
322
0
      break;
323
0
    }
324
0
    case IOCTL_SERIAL_GET_TIMEOUTS:
325
0
    {
326
0
      if (pServerSerialDriver->get_timeouts)
327
0
      {
328
0
        SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer;
329
330
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS));
331
0
        if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS))
332
0
        {
333
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
334
0
          return FALSE;
335
0
        }
336
337
0
        if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
338
0
          return FALSE;
339
340
0
        *lpBytesReturned = sizeof(SERIAL_TIMEOUTS);
341
0
        return TRUE;
342
0
      }
343
0
      break;
344
0
    }
345
0
    case IOCTL_SERIAL_SET_DTR:
346
0
    {
347
0
      if (pServerSerialDriver->set_dtr)
348
0
      {
349
0
        return pServerSerialDriver->set_dtr(pComm);
350
0
      }
351
0
      break;
352
0
    }
353
0
    case IOCTL_SERIAL_CLR_DTR:
354
0
    {
355
0
      if (pServerSerialDriver->clear_dtr)
356
0
      {
357
0
        return pServerSerialDriver->clear_dtr(pComm);
358
0
      }
359
0
      break;
360
0
    }
361
0
    case IOCTL_SERIAL_SET_RTS:
362
0
    {
363
0
      if (pServerSerialDriver->set_rts)
364
0
      {
365
0
        return pServerSerialDriver->set_rts(pComm);
366
0
      }
367
0
      break;
368
0
    }
369
0
    case IOCTL_SERIAL_CLR_RTS:
370
0
    {
371
0
      if (pServerSerialDriver->clear_rts)
372
0
      {
373
0
        return pServerSerialDriver->clear_rts(pComm);
374
0
      }
375
0
      break;
376
0
    }
377
0
    case IOCTL_SERIAL_GET_MODEMSTATUS:
378
0
    {
379
0
      if (pServerSerialDriver->get_modemstatus)
380
0
      {
381
0
        ULONG* pRegister = (ULONG*)lpOutBuffer;
382
383
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
384
0
        if (nOutBufferSize < sizeof(ULONG))
385
0
        {
386
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
387
0
          return FALSE;
388
0
        }
389
390
0
        if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
391
0
          return FALSE;
392
393
0
        *lpBytesReturned = sizeof(ULONG);
394
0
        return TRUE;
395
0
      }
396
0
      break;
397
0
    }
398
0
    case IOCTL_SERIAL_SET_WAIT_MASK:
399
0
    {
400
0
      if (pServerSerialDriver->set_wait_mask)
401
0
      {
402
0
        ULONG* pWaitMask = (ULONG*)lpInBuffer;
403
404
0
        WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
405
0
        if (nInBufferSize < sizeof(ULONG))
406
0
        {
407
0
          SetLastError(ERROR_INVALID_PARAMETER);
408
0
          return FALSE;
409
0
        }
410
411
0
        return pServerSerialDriver->set_wait_mask(pComm, pWaitMask);
412
0
      }
413
0
      break;
414
0
    }
415
0
    case IOCTL_SERIAL_GET_WAIT_MASK:
416
0
    {
417
0
      if (pServerSerialDriver->get_wait_mask)
418
0
      {
419
0
        ULONG* pWaitMask = (ULONG*)lpOutBuffer;
420
421
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
422
0
        if (nOutBufferSize < sizeof(ULONG))
423
0
        {
424
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
425
0
          return FALSE;
426
0
        }
427
428
0
        if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
429
0
          return FALSE;
430
431
0
        *lpBytesReturned = sizeof(ULONG);
432
0
        return TRUE;
433
0
      }
434
0
      break;
435
0
    }
436
0
    case IOCTL_SERIAL_WAIT_ON_MASK:
437
0
    {
438
0
      if (pServerSerialDriver->wait_on_mask)
439
0
      {
440
0
        ULONG* pOutputMask = (ULONG*)lpOutBuffer;
441
442
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
443
0
        if (nOutBufferSize < sizeof(ULONG))
444
0
        {
445
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
446
0
          return FALSE;
447
0
        }
448
449
0
        if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask))
450
0
        {
451
0
          *lpBytesReturned = sizeof(ULONG);
452
0
          return FALSE;
453
0
        }
454
455
0
        *lpBytesReturned = sizeof(ULONG);
456
0
        return TRUE;
457
0
      }
458
0
      break;
459
0
    }
460
0
    case IOCTL_SERIAL_SET_QUEUE_SIZE:
461
0
    {
462
0
      if (pServerSerialDriver->set_queue_size)
463
0
      {
464
0
        SERIAL_QUEUE_SIZE* pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer;
465
466
0
        WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE));
467
0
        if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE))
468
0
        {
469
0
          SetLastError(ERROR_INVALID_PARAMETER);
470
0
          return FALSE;
471
0
        }
472
473
0
        return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
474
0
      }
475
0
      break;
476
0
    }
477
0
    case IOCTL_SERIAL_PURGE:
478
0
    {
479
0
      if (pServerSerialDriver->purge)
480
0
      {
481
0
        ULONG* pPurgeMask = (ULONG*)lpInBuffer;
482
483
0
        WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
484
0
        if (nInBufferSize < sizeof(ULONG))
485
0
        {
486
0
          SetLastError(ERROR_INVALID_PARAMETER);
487
0
          return FALSE;
488
0
        }
489
490
0
        return pServerSerialDriver->purge(pComm, pPurgeMask);
491
0
      }
492
0
      break;
493
0
    }
494
0
    case IOCTL_SERIAL_GET_COMMSTATUS:
495
0
    {
496
0
      if (pServerSerialDriver->get_commstatus)
497
0
      {
498
0
        SERIAL_STATUS* pCommstatus = (SERIAL_STATUS*)lpOutBuffer;
499
500
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_STATUS));
501
0
        if (nOutBufferSize < sizeof(SERIAL_STATUS))
502
0
        {
503
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
504
0
          return FALSE;
505
0
        }
506
507
0
        if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
508
0
          return FALSE;
509
510
0
        *lpBytesReturned = sizeof(SERIAL_STATUS);
511
0
        return TRUE;
512
0
      }
513
0
      break;
514
0
    }
515
0
    case IOCTL_SERIAL_SET_BREAK_ON:
516
0
    {
517
0
      if (pServerSerialDriver->set_break_on)
518
0
      {
519
0
        return pServerSerialDriver->set_break_on(pComm);
520
0
      }
521
0
      break;
522
0
    }
523
0
    case IOCTL_SERIAL_SET_BREAK_OFF:
524
0
    {
525
0
      if (pServerSerialDriver->set_break_off)
526
0
      {
527
0
        return pServerSerialDriver->set_break_off(pComm);
528
0
      }
529
0
      break;
530
0
    }
531
0
    case IOCTL_SERIAL_SET_XOFF:
532
0
    {
533
0
      if (pServerSerialDriver->set_xoff)
534
0
      {
535
0
        return pServerSerialDriver->set_xoff(pComm);
536
0
      }
537
0
      break;
538
0
    }
539
0
    case IOCTL_SERIAL_SET_XON:
540
0
    {
541
0
      if (pServerSerialDriver->set_xon)
542
0
      {
543
0
        return pServerSerialDriver->set_xon(pComm);
544
0
      }
545
0
      break;
546
0
    }
547
0
    case IOCTL_SERIAL_GET_DTRRTS:
548
0
    {
549
0
      if (pServerSerialDriver->get_dtrrts)
550
0
      {
551
0
        ULONG* pMask = (ULONG*)lpOutBuffer;
552
553
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
554
0
        if (nOutBufferSize < sizeof(ULONG))
555
0
        {
556
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
557
0
          return FALSE;
558
0
        }
559
560
0
        if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
561
0
          return FALSE;
562
563
0
        *lpBytesReturned = sizeof(ULONG);
564
0
        return TRUE;
565
0
      }
566
0
      break;
567
0
    }
568
0
    case IOCTL_SERIAL_CONFIG_SIZE:
569
0
    {
570
0
      if (pServerSerialDriver->config_size)
571
0
      {
572
0
        ULONG* pSize = (ULONG*)lpOutBuffer;
573
574
0
        WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
575
0
        if (nOutBufferSize < sizeof(ULONG))
576
0
        {
577
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
578
0
          return FALSE;
579
0
        }
580
581
0
        if (!pServerSerialDriver->config_size(pComm, pSize))
582
0
          return FALSE;
583
584
0
        *lpBytesReturned = sizeof(ULONG);
585
0
        return TRUE;
586
0
      }
587
0
      break;
588
0
    }
589
0
    case IOCTL_SERIAL_IMMEDIATE_CHAR:
590
0
    {
591
0
      if (pServerSerialDriver->immediate_char)
592
0
      {
593
0
        UCHAR* pChar = (UCHAR*)lpInBuffer;
594
595
0
        WINPR_ASSERT(nInBufferSize >= sizeof(UCHAR));
596
0
        if (nInBufferSize < sizeof(UCHAR))
597
0
        {
598
0
          SetLastError(ERROR_INVALID_PARAMETER);
599
0
          return FALSE;
600
0
        }
601
602
0
        return pServerSerialDriver->immediate_char(pComm, pChar);
603
0
      }
604
0
      break;
605
0
    }
606
0
    case IOCTL_SERIAL_RESET_DEVICE:
607
0
    {
608
0
      if (pServerSerialDriver->reset_device)
609
0
      {
610
0
        return pServerSerialDriver->reset_device(pComm);
611
0
      }
612
0
      break;
613
0
    }
614
0
  }
615
616
0
  CommLog_Print(
617
0
      WLOG_WARN, _T("unsupported IoControlCode=[0x%08" PRIX32 "] %s (remote serial driver: %s)"),
618
0
      dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name);
619
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */
620
0
  return FALSE;
621
0
}
622
623
/**
624
 * FIXME: to be used through winpr-io's DeviceIoControl
625
 *
626
 * Any previous error as returned by GetLastError is cleared.
627
 *
628
 * ERRORS:
629
 *   ERROR_INVALID_HANDLE
630
 *   ERROR_INVALID_PARAMETER
631
 *   ERROR_NOT_SUPPORTED lpOverlapped is not supported
632
 *   ERROR_INSUFFICIENT_BUFFER
633
 *   ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl
634
 */
635
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
636
                         DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
637
                         LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
638
0
{
639
0
  WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
640
0
  BOOL result = 0;
641
642
0
  if (hDevice == INVALID_HANDLE_VALUE)
643
0
  {
644
0
    SetLastError(ERROR_INVALID_HANDLE);
645
0
    return FALSE;
646
0
  }
647
648
0
  if (!CommIsHandled(hDevice))
649
0
    return FALSE;
650
651
0
  if (!pComm->fd)
652
0
  {
653
0
    SetLastError(ERROR_INVALID_HANDLE);
654
0
    return FALSE;
655
0
  }
656
657
0
  result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
658
0
                                 nOutBufferSize, lpBytesReturned, lpOverlapped);
659
660
0
  if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
661
0
  {
662
    /* This might be a hint for a bug, especially when result==TRUE */
663
0
    CommLog_Print(WLOG_WARN,
664
0
                  "lpBytesReturned=%" PRIu32 " and nOutBufferSize=%" PRIu32 " are different!",
665
0
                  *lpBytesReturned, nOutBufferSize);
666
0
  }
667
668
0
  if (pComm->permissive)
669
0
  {
670
0
    if (!result)
671
0
    {
672
0
      CommLog_Print(
673
0
          WLOG_WARN,
674
0
          "[permissive]: whereas it failed, made to succeed IoControlCode=[0x%08" PRIX32
675
0
          "] %s, last-error: 0x%08" PRIX32 "",
676
0
          dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError());
677
0
    }
678
679
0
    return TRUE; /* always! */
680
0
  }
681
682
0
  return result;
683
0
}
684
685
int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
686
0
{
687
0
  int result = 0;
688
0
  struct termios currentState = { 0 };
689
690
0
  if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
691
0
  {
692
0
    CommLog_Print(WLOG_WARN, "tcsetattr failure, errno: %d", errno);
693
0
    return result;
694
0
  }
695
696
  /* NB: tcsetattr() can succeed even if not all changes have been applied. */
697
0
  if ((result = tcgetattr(fd, &currentState)) < 0)
698
0
  {
699
0
    CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno);
700
0
    return result;
701
0
  }
702
703
0
  if (memcmp(&currentState, termios_p, sizeof(struct termios)) != 0)
704
0
  {
705
0
    CommLog_Print(WLOG_DEBUG,
706
0
                  "all termios parameters are not set yet, doing a second attempt...");
707
0
    if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
708
0
    {
709
0
      CommLog_Print(WLOG_WARN, "2nd tcsetattr failure, errno: %d", errno);
710
0
      return result;
711
0
    }
712
713
0
    ZeroMemory(&currentState, sizeof(struct termios));
714
0
    if ((result = tcgetattr(fd, &currentState)) < 0)
715
0
    {
716
0
      CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno);
717
0
      return result;
718
0
    }
719
720
0
    if (memcmp(&currentState, termios_p, sizeof(struct termios)) != 0)
721
0
    {
722
0
      CommLog_Print(WLOG_WARN,
723
0
                    "Failure: all termios parameters are still not set on a second attempt");
724
0
      return -1;
725
0
    }
726
0
  }
727
728
0
  return 0;
729
0
}
730
731
#endif /* __linux__ */