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] = { 0 };
58 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
61 if (!CommIsHandleValid(hDevice))
66 SetLastError(ERROR_NOT_SUPPORTED);
70 if (lpBytesReturned == NULL)
72 SetLastError(ERROR_INVALID_PARAMETER);
77 SetLastError(ERROR_SUCCESS);
81 CommLog_Print(WLOG_DEBUG,
"CommDeviceIoControl: IoControlCode: %s [0x%08" PRIx32
"]",
82 _comm_serial_ioctl_name(dwIoControlCode), dwIoControlCode);
88 switch (pComm->serverSerialDriverId)
90 case SerialDriverSerialSys:
91 pServerSerialDriver = SerialSys_s();
94 case SerialDriverSerCxSys:
95 pServerSerialDriver = SerCxSys_s();
98 case SerialDriverSerCx2Sys:
99 pServerSerialDriver = SerCx2Sys_s();
102 case SerialDriverUnknown:
104 CommLog_Print(WLOG_DEBUG,
"Unknown remote serial driver (%d), using SerCx2.sys",
105 pComm->serverSerialDriverId);
106 pServerSerialDriver = SerCx2Sys_s();
110 WINPR_ASSERT(pServerSerialDriver != NULL);
112 switch (dwIoControlCode)
114 case IOCTL_USBPRINT_GET_1284_ID:
118 *lpBytesReturned = nOutBufferSize;
119 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
122 case IOCTL_SERIAL_SET_BAUD_RATE:
124 if (pServerSerialDriver->set_baud_rate)
131 SetLastError(ERROR_INVALID_PARAMETER);
135 return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
139 case IOCTL_SERIAL_GET_BAUD_RATE:
141 if (pServerSerialDriver->get_baud_rate)
148 SetLastError(ERROR_INSUFFICIENT_BUFFER);
152 if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
160 case IOCTL_SERIAL_GET_PROPERTIES:
162 if (pServerSerialDriver->get_properties)
166 WINPR_ASSERT(nOutBufferSize >=
sizeof(
COMMPROP));
167 if (nOutBufferSize <
sizeof(
COMMPROP))
169 SetLastError(ERROR_INSUFFICIENT_BUFFER);
173 if (!pServerSerialDriver->get_properties(pComm, pProperties))
176 *lpBytesReturned =
sizeof(
COMMPROP);
181 case IOCTL_SERIAL_SET_CHARS:
183 if (pServerSerialDriver->set_serial_chars)
190 SetLastError(ERROR_INVALID_PARAMETER);
194 return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
198 case IOCTL_SERIAL_GET_CHARS:
200 if (pServerSerialDriver->get_serial_chars)
207 SetLastError(ERROR_INSUFFICIENT_BUFFER);
211 if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
219 case IOCTL_SERIAL_SET_LINE_CONTROL:
221 if (pServerSerialDriver->set_line_control)
228 SetLastError(ERROR_INVALID_PARAMETER);
232 return pServerSerialDriver->set_line_control(pComm, pLineControl);
236 case IOCTL_SERIAL_GET_LINE_CONTROL:
238 if (pServerSerialDriver->get_line_control)
245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
249 if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
257 case IOCTL_SERIAL_SET_HANDFLOW:
259 if (pServerSerialDriver->set_handflow)
266 SetLastError(ERROR_INVALID_PARAMETER);
270 return pServerSerialDriver->set_handflow(pComm, pHandflow);
274 case IOCTL_SERIAL_GET_HANDFLOW:
276 if (pServerSerialDriver->get_handflow)
283 SetLastError(ERROR_INSUFFICIENT_BUFFER);
287 if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
295 case IOCTL_SERIAL_SET_TIMEOUTS:
297 if (pServerSerialDriver->set_timeouts)
304 SetLastError(ERROR_INVALID_PARAMETER);
308 return pServerSerialDriver->set_timeouts(pComm, pHandflow);
312 case IOCTL_SERIAL_GET_TIMEOUTS:
314 if (pServerSerialDriver->get_timeouts)
321 SetLastError(ERROR_INSUFFICIENT_BUFFER);
325 if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
333 case IOCTL_SERIAL_SET_DTR:
335 if (pServerSerialDriver->set_dtr)
337 return pServerSerialDriver->set_dtr(pComm);
341 case IOCTL_SERIAL_CLR_DTR:
343 if (pServerSerialDriver->clear_dtr)
345 return pServerSerialDriver->clear_dtr(pComm);
349 case IOCTL_SERIAL_SET_RTS:
351 if (pServerSerialDriver->set_rts)
353 return pServerSerialDriver->set_rts(pComm);
357 case IOCTL_SERIAL_CLR_RTS:
359 if (pServerSerialDriver->clear_rts)
361 return pServerSerialDriver->clear_rts(pComm);
365 case IOCTL_SERIAL_GET_MODEMSTATUS:
367 if (pServerSerialDriver->get_modemstatus)
369 ULONG* pRegister = (ULONG*)lpOutBuffer;
371 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
372 if (nOutBufferSize <
sizeof(ULONG))
374 SetLastError(ERROR_INSUFFICIENT_BUFFER);
378 if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
381 CommLog_Print(WLOG_DEBUG,
"modem status %s" PRIx32,
382 comm_ioctl_modem_status_string(*pRegister, buffer,
sizeof(buffer)));
383 *lpBytesReturned =
sizeof(ULONG);
388 case IOCTL_SERIAL_SET_WAIT_MASK:
390 if (pServerSerialDriver->set_wait_mask)
392 ULONG* pWaitMask = (ULONG*)lpInBuffer;
394 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
395 if (nInBufferSize <
sizeof(ULONG))
397 SetLastError(ERROR_INVALID_PARAMETER);
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);
408 case IOCTL_SERIAL_GET_WAIT_MASK:
410 if (pServerSerialDriver->get_wait_mask)
412 ULONG* pWaitMask = (ULONG*)lpOutBuffer;
414 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
415 if (nOutBufferSize <
sizeof(ULONG))
417 SetLastError(ERROR_INSUFFICIENT_BUFFER);
421 if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
424 CommLog_Print(WLOG_DEBUG,
"get_wait_mask %s",
425 CommSerialEvString(*pWaitMask, buffer,
sizeof(buffer)));
426 *lpBytesReturned =
sizeof(ULONG);
431 case IOCTL_SERIAL_WAIT_ON_MASK:
433 if (pServerSerialDriver->wait_on_mask)
435 ULONG* pOutputMask = (ULONG*)lpOutBuffer;
437 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
438 if (nOutBufferSize <
sizeof(ULONG))
440 SetLastError(ERROR_INSUFFICIENT_BUFFER);
444 const BOOL rc = pServerSerialDriver->wait_on_mask(pComm, pOutputMask);
446 *lpBytesReturned =
sizeof(ULONG);
447 CommLog_Print(WLOG_DEBUG,
"wait_on_mask %s -> %d",
448 CommSerialEvString(*pOutputMask, buffer,
sizeof(buffer)), rc);
453 case IOCTL_SERIAL_SET_QUEUE_SIZE:
455 if (pServerSerialDriver->set_queue_size)
462 SetLastError(ERROR_INVALID_PARAMETER);
466 return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
470 case IOCTL_SERIAL_PURGE:
472 if (pServerSerialDriver->purge)
474 ULONG* pPurgeMask = (ULONG*)lpInBuffer;
476 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
477 if (nInBufferSize <
sizeof(ULONG))
479 SetLastError(ERROR_INVALID_PARAMETER);
483 return pServerSerialDriver->purge(pComm, pPurgeMask);
487 case IOCTL_SERIAL_GET_COMMSTATUS:
489 if (pServerSerialDriver->get_commstatus)
496 SetLastError(ERROR_INSUFFICIENT_BUFFER);
500 if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
508 case IOCTL_SERIAL_SET_BREAK_ON:
510 if (pServerSerialDriver->set_break_on)
512 return pServerSerialDriver->set_break_on(pComm);
516 case IOCTL_SERIAL_SET_BREAK_OFF:
518 if (pServerSerialDriver->set_break_off)
520 return pServerSerialDriver->set_break_off(pComm);
524 case IOCTL_SERIAL_SET_XOFF:
526 if (pServerSerialDriver->set_xoff)
528 return pServerSerialDriver->set_xoff(pComm);
532 case IOCTL_SERIAL_SET_XON:
534 if (pServerSerialDriver->set_xon)
536 return pServerSerialDriver->set_xon(pComm);
540 case IOCTL_SERIAL_GET_DTRRTS:
542 if (pServerSerialDriver->get_dtrrts)
544 ULONG* pMask = (ULONG*)lpOutBuffer;
546 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
547 if (nOutBufferSize <
sizeof(ULONG))
549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
553 if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
556 *lpBytesReturned =
sizeof(ULONG);
561 case IOCTL_SERIAL_CONFIG_SIZE:
563 if (pServerSerialDriver->config_size)
565 ULONG* pSize = (ULONG*)lpOutBuffer;
567 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
568 if (nOutBufferSize <
sizeof(ULONG))
570 SetLastError(ERROR_INSUFFICIENT_BUFFER);
574 if (!pServerSerialDriver->config_size(pComm, pSize))
577 *lpBytesReturned =
sizeof(ULONG);
582 case IOCTL_SERIAL_IMMEDIATE_CHAR:
584 if (pServerSerialDriver->immediate_char)
586 UCHAR* pChar = (UCHAR*)lpInBuffer;
588 WINPR_ASSERT(nInBufferSize >=
sizeof(UCHAR));
589 if (nInBufferSize <
sizeof(UCHAR))
591 SetLastError(ERROR_INVALID_PARAMETER);
595 return pServerSerialDriver->immediate_char(pComm, pChar);
599 case IOCTL_SERIAL_RESET_DEVICE:
601 if (pServerSerialDriver->reset_device)
603 return pServerSerialDriver->reset_device(pComm);
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);
630BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
631 DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
634 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
637 if (hDevice == INVALID_HANDLE_VALUE)
639 SetLastError(ERROR_INVALID_HANDLE);
643 if (!CommIsHandled(hDevice))
648 SetLastError(ERROR_INVALID_HANDLE);
652 result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
653 nOutBufferSize, lpBytesReturned, lpOverlapped);
655 if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
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,
665 if (pComm->permissive)
669 CommLog_Print(WLOG_WARN,
670 "[permissive]: IoControlCode=[0x%08" PRIX32
"] %s failed, ignoring",
671 dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode));
680int comm_ioctl_tcsetattr(
int fd,
int optional_actions,
const struct termios* termios_p)
682 struct termios currentState = { 0 };
686 const int src = tcsetattr(fd, optional_actions, termios_p);
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);
696 const int rrc = tcgetattr(fd, ¤tState);
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);
705 }
while ((memcmp(¤tState, termios_p,
sizeof(
struct termios)) != 0) && (count++ < 2));
710static const char* comm_ioctl_modem_flag_str(ULONG flag)
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";
723 return "SERIAL_MSR_CTS";
725 return "SERIAL_MSR_DSR";
727 return "SERIAL_MSR_RI";
729 return "SERIAL_MSR_DCD";
731 return "SERIAL_MSR_UNKNOWN";
735const char* comm_ioctl_modem_status_string(ULONG status,
char* buffer,
size_t size)
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
741 winpr_str_append(
"{", buffer, size,
"");
743 const char* sep =
"";
744 for (
size_t x = 0; x < ARRAYSIZE(flags); x++)
746 const ULONG flag = flags[x];
749 winpr_str_append(comm_ioctl_modem_flag_str(flag), buffer, size, sep);
754 char number[32] = { 0 };
755 (void)_snprintf(number,
sizeof(number),
"}[0x%08" PRIx32
"]", status);
756 winpr_str_append(number, buffer, size,
"");