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