Coverage Report

Created: 2023-09-25 06:56

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