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