23#include <winpr/config.h>
25#include <winpr/assert.h>
28#include <winpr/wlog.h>
31#include "comm_ioctl.h"
32#include "comm_serial_sys.h"
33#include "comm_sercx_sys.h"
34#include "comm_sercx2_sys.h"
36static const char* comm_ioctl_modem_status_string(ULONG status,
char* buffer,
size_t size);
53static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
54 DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
57 char buffer[128] = WINPR_C_ARRAY_INIT;
58 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
61 if (!CommIsHandleValid(hDevice))
66 SetLastError(ERROR_NOT_SUPPORTED);
70 if (lpBytesReturned ==
nullptr)
73 ERROR_INVALID_PARAMETER);
78 SetLastError(ERROR_SUCCESS);
82 CommLog_Print(WLOG_DEBUG,
"CommDeviceIoControl: IoControlCode: %s [0x%08" PRIx32
"]",
83 _comm_serial_ioctl_name(dwIoControlCode), dwIoControlCode);
89 switch (pComm->serverSerialDriverId)
91 case SerialDriverSerialSys:
92 pServerSerialDriver = SerialSys_s();
95 case SerialDriverSerCxSys:
96 pServerSerialDriver = SerCxSys_s();
99 case SerialDriverSerCx2Sys:
100 pServerSerialDriver = SerCx2Sys_s();
103 case SerialDriverUnknown:
105 CommLog_Print(WLOG_DEBUG,
"Unknown remote serial driver (%u), using SerCx2.sys",
106 pComm->serverSerialDriverId);
107 pServerSerialDriver = SerCx2Sys_s();
111 WINPR_ASSERT(pServerSerialDriver !=
nullptr);
113 switch (dwIoControlCode)
115 case IOCTL_USBPRINT_GET_1284_ID:
119 *lpBytesReturned = nOutBufferSize;
120 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
123 case IOCTL_SERIAL_SET_BAUD_RATE:
125 if (pServerSerialDriver->set_baud_rate)
132 SetLastError(ERROR_INVALID_PARAMETER);
136 return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
140 case IOCTL_SERIAL_GET_BAUD_RATE:
142 if (pServerSerialDriver->get_baud_rate)
149 SetLastError(ERROR_INSUFFICIENT_BUFFER);
153 if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
161 case IOCTL_SERIAL_GET_PROPERTIES:
163 if (pServerSerialDriver->get_properties)
167 WINPR_ASSERT(nOutBufferSize >=
sizeof(
COMMPROP));
168 if (nOutBufferSize <
sizeof(
COMMPROP))
170 SetLastError(ERROR_INSUFFICIENT_BUFFER);
174 if (!pServerSerialDriver->get_properties(pComm, pProperties))
177 *lpBytesReturned =
sizeof(
COMMPROP);
182 case IOCTL_SERIAL_SET_CHARS:
184 if (pServerSerialDriver->set_serial_chars)
191 SetLastError(ERROR_INVALID_PARAMETER);
195 return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
199 case IOCTL_SERIAL_GET_CHARS:
201 if (pServerSerialDriver->get_serial_chars)
208 SetLastError(ERROR_INSUFFICIENT_BUFFER);
212 if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
220 case IOCTL_SERIAL_SET_LINE_CONTROL:
222 if (pServerSerialDriver->set_line_control)
229 SetLastError(ERROR_INVALID_PARAMETER);
233 return pServerSerialDriver->set_line_control(pComm, pLineControl);
237 case IOCTL_SERIAL_GET_LINE_CONTROL:
239 if (pServerSerialDriver->get_line_control)
246 SetLastError(ERROR_INSUFFICIENT_BUFFER);
250 if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
258 case IOCTL_SERIAL_SET_HANDFLOW:
260 if (pServerSerialDriver->set_handflow)
267 SetLastError(ERROR_INVALID_PARAMETER);
271 return pServerSerialDriver->set_handflow(pComm, pHandflow);
275 case IOCTL_SERIAL_GET_HANDFLOW:
277 if (pServerSerialDriver->get_handflow)
284 SetLastError(ERROR_INSUFFICIENT_BUFFER);
288 if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
296 case IOCTL_SERIAL_SET_TIMEOUTS:
298 if (pServerSerialDriver->set_timeouts)
305 SetLastError(ERROR_INVALID_PARAMETER);
309 return pServerSerialDriver->set_timeouts(pComm, pHandflow);
313 case IOCTL_SERIAL_GET_TIMEOUTS:
315 if (pServerSerialDriver->get_timeouts)
322 SetLastError(ERROR_INSUFFICIENT_BUFFER);
326 if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
334 case IOCTL_SERIAL_SET_DTR:
336 if (pServerSerialDriver->set_dtr)
338 return pServerSerialDriver->set_dtr(pComm);
342 case IOCTL_SERIAL_CLR_DTR:
344 if (pServerSerialDriver->clear_dtr)
346 return pServerSerialDriver->clear_dtr(pComm);
350 case IOCTL_SERIAL_SET_RTS:
352 if (pServerSerialDriver->set_rts)
354 return pServerSerialDriver->set_rts(pComm);
358 case IOCTL_SERIAL_CLR_RTS:
360 if (pServerSerialDriver->clear_rts)
362 return pServerSerialDriver->clear_rts(pComm);
366 case IOCTL_SERIAL_GET_MODEMSTATUS:
368 if (pServerSerialDriver->get_modemstatus)
370 ULONG* pRegister = (ULONG*)lpOutBuffer;
372 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
373 if (nOutBufferSize <
sizeof(ULONG))
375 SetLastError(ERROR_INSUFFICIENT_BUFFER);
379 if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
382 CommLog_Print(WLOG_DEBUG,
"modem status %s" PRIx32,
383 comm_ioctl_modem_status_string(*pRegister, buffer,
sizeof(buffer)));
384 *lpBytesReturned =
sizeof(ULONG);
389 case IOCTL_SERIAL_SET_WAIT_MASK:
391 if (pServerSerialDriver->set_wait_mask)
393 ULONG* pWaitMask = (ULONG*)lpInBuffer;
395 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
396 if (nInBufferSize <
sizeof(ULONG))
398 SetLastError(ERROR_INVALID_PARAMETER);
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);
409 case IOCTL_SERIAL_GET_WAIT_MASK:
411 if (pServerSerialDriver->get_wait_mask)
413 ULONG* pWaitMask = (ULONG*)lpOutBuffer;
415 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
416 if (nOutBufferSize <
sizeof(ULONG))
418 SetLastError(ERROR_INSUFFICIENT_BUFFER);
422 if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
425 CommLog_Print(WLOG_DEBUG,
"get_wait_mask %s",
426 CommSerialEvString(*pWaitMask, buffer,
sizeof(buffer)));
427 *lpBytesReturned =
sizeof(ULONG);
432 case IOCTL_SERIAL_WAIT_ON_MASK:
434 if (pServerSerialDriver->wait_on_mask)
436 ULONG* pOutputMask = (ULONG*)lpOutBuffer;
438 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
439 if (nOutBufferSize <
sizeof(ULONG))
441 SetLastError(ERROR_INSUFFICIENT_BUFFER);
445 const BOOL rc = pServerSerialDriver->wait_on_mask(pComm, pOutputMask);
447 *lpBytesReturned =
sizeof(ULONG);
448 CommLog_Print(WLOG_DEBUG,
"wait_on_mask %s -> %d",
449 CommSerialEvString(*pOutputMask, buffer,
sizeof(buffer)), rc);
454 case IOCTL_SERIAL_SET_QUEUE_SIZE:
456 if (pServerSerialDriver->set_queue_size)
463 SetLastError(ERROR_INVALID_PARAMETER);
467 return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
471 case IOCTL_SERIAL_PURGE:
473 if (pServerSerialDriver->purge)
475 ULONG* pPurgeMask = (ULONG*)lpInBuffer;
477 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
478 if (nInBufferSize <
sizeof(ULONG))
480 SetLastError(ERROR_INVALID_PARAMETER);
484 return pServerSerialDriver->purge(pComm, pPurgeMask);
488 case IOCTL_SERIAL_GET_COMMSTATUS:
490 if (pServerSerialDriver->get_commstatus)
497 SetLastError(ERROR_INSUFFICIENT_BUFFER);
501 if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
509 case IOCTL_SERIAL_SET_BREAK_ON:
511 if (pServerSerialDriver->set_break_on)
513 return pServerSerialDriver->set_break_on(pComm);
517 case IOCTL_SERIAL_SET_BREAK_OFF:
519 if (pServerSerialDriver->set_break_off)
521 return pServerSerialDriver->set_break_off(pComm);
525 case IOCTL_SERIAL_SET_XOFF:
527 if (pServerSerialDriver->set_xoff)
529 return pServerSerialDriver->set_xoff(pComm);
533 case IOCTL_SERIAL_SET_XON:
535 if (pServerSerialDriver->set_xon)
537 return pServerSerialDriver->set_xon(pComm);
541 case IOCTL_SERIAL_GET_DTRRTS:
543 if (pServerSerialDriver->get_dtrrts)
545 ULONG* pMask = (ULONG*)lpOutBuffer;
547 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
548 if (nOutBufferSize <
sizeof(ULONG))
550 SetLastError(ERROR_INSUFFICIENT_BUFFER);
554 if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
557 *lpBytesReturned =
sizeof(ULONG);
562 case IOCTL_SERIAL_CONFIG_SIZE:
564 if (pServerSerialDriver->config_size)
566 ULONG* pSize = (ULONG*)lpOutBuffer;
568 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
569 if (nOutBufferSize <
sizeof(ULONG))
571 SetLastError(ERROR_INSUFFICIENT_BUFFER);
575 if (!pServerSerialDriver->config_size(pComm, pSize))
578 *lpBytesReturned =
sizeof(ULONG);
583 case IOCTL_SERIAL_IMMEDIATE_CHAR:
585 if (pServerSerialDriver->immediate_char)
587 UCHAR* pChar = (UCHAR*)lpInBuffer;
589 WINPR_ASSERT(nInBufferSize >=
sizeof(UCHAR));
590 if (nInBufferSize <
sizeof(UCHAR))
592 SetLastError(ERROR_INVALID_PARAMETER);
596 return pServerSerialDriver->immediate_char(pComm, pChar);
600 case IOCTL_SERIAL_RESET_DEVICE:
602 if (pServerSerialDriver->reset_device)
604 return pServerSerialDriver->reset_device(pComm);
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);
631BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
632 DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
635 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
638 if (hDevice == INVALID_HANDLE_VALUE)
640 SetLastError(ERROR_INVALID_HANDLE);
644 if (!CommIsHandled(hDevice))
649 SetLastError(ERROR_INVALID_HANDLE);
653 result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
654 nOutBufferSize, lpBytesReturned, lpOverlapped);
656 if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
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,
666 if (pComm->permissive)
670 CommLog_Print(WLOG_WARN,
671 "[permissive]: IoControlCode=[0x%08" PRIX32
"] %s failed, ignoring",
672 dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode));
681int comm_ioctl_tcsetattr(
int fd,
int optional_actions,
const struct termios* termios_p)
683 struct termios currentState = WINPR_C_ARRAY_INIT;
687 const int src = tcsetattr(fd, optional_actions, termios_p);
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);
697 const int rrc = tcgetattr(fd, ¤tState);
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);
706 }
while ((memcmp(¤tState, termios_p,
sizeof(
struct termios)) != 0) && (count++ < 2));
711static const char* comm_ioctl_modem_flag_str(ULONG flag)
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";
724 return "SERIAL_MSR_CTS";
726 return "SERIAL_MSR_DSR";
728 return "SERIAL_MSR_RI";
730 return "SERIAL_MSR_DCD";
732 return "SERIAL_MSR_UNKNOWN";
736const char* comm_ioctl_modem_status_string(ULONG status,
char* buffer,
size_t size)
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
742 winpr_str_append(
"{", buffer, size,
"");
744 const char* sep =
"";
745 for (
size_t x = 0; x < ARRAYSIZE(flags); x++)
747 const ULONG flag = flags[x];
750 winpr_str_append(comm_ioctl_modem_flag_str(flag), buffer, size, sep);
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,
"");