// // rfc2217.c // // // Typically a client will use WILL and WONT, while and access server // will use DO and DONT. // #include "pch.h" void EscWriteChar( PCPR_DEVICE_EXTENSION devExt, unsigned char C ); void SendStr( PCPR_DEVICE_EXTENSION devExt, char * Str ); void SendSignature( PCPR_DEVICE_EXTENSION devExt, char * Sig ); void HandleCPCCommand( PCPR_DEVICE_EXTENSION devExt ); void HandleIACCommand( PCPR_DEVICE_EXTENSION devExt ); void SetPortDataSize( PCPR_DEVICE_EXTENSION devExt, unsigned char DataSize ); void SetModemState( PCPR_DEVICE_EXTENSION devExt, unsigned char MState ); void SetLineState( PCPR_DEVICE_EXTENSION devExt, unsigned char LState ); void SetPortParity( PCPR_DEVICE_EXTENSION devExt, unsigned char Parity ); void SetPortStopSize( PCPR_DEVICE_EXTENSION devExt, unsigned char StopSize ); void SetPortFlowControl( PCPR_DEVICE_EXTENSION devExt, unsigned char How); void SetPortSpeed( PCPR_DEVICE_EXTENSION devExt, unsigned long BaudRate ); LogModemState( PCPR_DEVICE_EXTENSION devExt, unsigned char mstate ); LogLineState( PCPR_DEVICE_EXTENSION devExt, unsigned char lstate ); // // =========================================================================== // Buffer manipulation functions that are NOT needed: // =========================================================================== // /* Initialize a buffer for operation */ void InitBuffer(CPR_BUFFER_TYPE * B) { /* Set the initial buffer positions */ B->RdPos = 0; B->WrPos = 0; } /* Check if the buffer is empty */ Boolean IsBufferEmpty(CPR_BUFFER_TYPE * B) { return((Boolean) B->RdPos == B->WrPos); } /* Check if the buffer is full */ Boolean IsBufferFull(CPR_BUFFER_TYPE * B) { /* We consider the buffer to be filled when there are 100 bytes left This is so even a full buffer can safely have escaped characters added to it. */ return((Boolean) B->WrPos == (B->RdPos + TN_BufferSize - 101) % TN_BufferSize); } /* Add a byte to a buffer */ void AddToBuffer(CPR_BUFFER_TYPE * B, unsigned char C) { B->Buffer[B->WrPos] = C; B->WrPos = (B->WrPos + 1) % TN_BufferSize; } void PushToBuffer(CPR_BUFFER_TYPE * B, unsigned char C) { if (B->RdPos > 0) B->RdPos--; else B->RdPos = TN_BufferSize - 1; B->Buffer[B->RdPos] = C; } /* Get a byte from a buffer */ unsigned char GetFromBuffer(CPR_BUFFER_TYPE * B) { unsigned char C = B->Buffer[B->RdPos]; B->RdPos = (B->RdPos + 1) % TN_BufferSize; return(C); } unsigned long int CprRfc2217_GetPortSpeed( PCPR_DEVICE_EXTENSION devExt ) { return devExt->BaudRate; } /* Retrieves the data size from PortFd */ // This method is called with SerialLock held unsigned char CprRfc2217_GetPortDataSize( PCPR_DEVICE_EXTENSION devExt ) { unsigned char dataSize; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // CprAcquireSerialSpinLock(devExt, &oldIrql); if ((devExt->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_5_DATA) { dataSize = 5; } else if ((devExt->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_6_DATA) { dataSize = 6; } else if ((devExt->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_7_DATA) { dataSize = 7; } else if ((devExt->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_8_DATA) { dataSize = 8; } // CprReleaseSerialSpinLock(devExt->SerialLock); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return dataSize; } /* Retrieves the parity settings from PortFd */ // This method is called with SerialLock held unsigned char CprRfc2217_GetPortParity( PCPR_DEVICE_EXTENSION devExt ) { // // Convert to Ones Base. // unsigned char parity; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // CprAcquireSerialSpinLock(devExt, &oldIrql); if ((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_NONE_PARITY) { parity = NO_PARITY + 1; } else if ((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_ODD_PARITY) { parity = ODD_PARITY + 1; } else if ((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_EVEN_PARITY) { parity = EVEN_PARITY + 1; } else if ((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_MARK_PARITY) { parity = MARK_PARITY + 1; } else if ((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_SPACE_PARITY) { parity = SPACE_PARITY + 1; } // CprReleaseSerialSpinLock(devExt->SerialLock); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return parity; } /* Retrieves the stop bits size from PortFd */ // This method is called with SerialLock held unsigned char CprRfc2217_GetPortStopSize( PCPR_DEVICE_EXTENSION devExt ) { unsigned char stopSize; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // CprAcquireSerialSpinLock(devExt, &oldIrql); if (devExt->LineControl & CPR_UART_LCR_2_STOP) { if (CprRfc2217_GetPortDataSize(devExt) == 5) { stopSize = 3; //STOP_BITS_1_5; } else { stopSize = 2; //STOP_BITS_2; } } else { stopSize = 1; //STOP_BIT_1; } // CprReleaseSerialSpinLock(devExt->SerialLock); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return stopSize; } /* Retrieves the flow control status, including DTR and RTS status, from PortFd */ unsigned char CprRfc2217_GetPortFlowControl( PCPR_DEVICE_EXTENSION devExt, unsigned char Which ) { //struct termios PortSettings; //int MLines; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); ///* Gets the basic informations from the port */ //tcgetattr(PortFd,&PortSettings); //ioctl(PortFd,TIOCMGET,&MLines); ///* Check which kind of information is requested */ #if 0 switch (Which) { /* Com Port Flow Control Setting (outbound/both) */ case 0: if (PortSettings.c_iflag & IXON) return((unsigned char) 2); if (PortSettings.c_cflag & CRTSCTS) return((unsigned char) 3); return((unsigned char) 1); break; /* BREAK State */ case 4: if (devExt->BreakSignaled == True) return((unsigned char) 5); else return((unsigned char) 6); break; /* DTR Signal State */ case 7: if (MLines & TIOCM_DTR) return((unsigned char) 8); else return((unsigned char) 9); break; /* RTS Signal State */ case 10: if (MLines & TIOCM_RTS) return((unsigned char) 11); else return((unsigned char) 12); break; /* Com Port Flow Control Setting (inbound) */ case 13: if (PortSettings.c_iflag & IXOFF) return((unsigned char) 15); if (PortSettings.c_cflag & CRTSCTS) return((unsigned char) 16); return((unsigned char) 14); break; default: if (PortSettings.c_iflag & IXON) return((unsigned char) 2); if (PortSettings.c_cflag & CRTSCTS) return((unsigned char) 3); return((unsigned char) 1); break; } #else CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return 0; #endif //struct termios PortSettings; //int MLines; ///* Gets the basic informations from the port */ //tcgetattr(PortFd,&PortSettings); //ioctl(PortFd,TIOCMGET,&MLines); ///* Check wich kind of information is requested */ //switch (Which) //{ // /* Com Port Flow Control Setting (outbound/both) */ // case 0: // if (PortSettings.c_iflag & IXON) // return((unsigned char) 2); // if (PortSettings.c_cflag & CRTSCTS) // return((unsigned char) 3); // return((unsigned char) 1); // break; // /* BREAK State */ // case 4: // if (BreakSignaled == True) // return((unsigned char) 5); // else // return((unsigned char) 6); // break; // /* DTR Signal State */ // case 7: // if (MLines & TIOCM_DTR) // return((unsigned char) 8); // else // return((unsigned char) 9); // break; // /* RTS Signal State */ // case 10: // if (MLines & TIOCM_RTS) // return((unsigned char) 11); // else // return((unsigned char) 12); // break; // /* Com Port Flow Control Setting (inbound) */ // case 13: // if (PortSettings.c_iflag & IXOFF) // return((unsigned char) 15); // if (PortSettings.c_cflag & CRTSCTS) // return((unsigned char) 16); // return((unsigned char) 14); // break; // default: // if (PortSettings.c_iflag & IXON) // return((unsigned char) 2); // if (PortSettings.c_cflag & CRTSCTS) // return((unsigned char) 3); // return((unsigned char) 1); // break; //} } // This method is called with SerialLock held void SetModemState( PCPR_DEVICE_EXTENSION devExt, unsigned char MState ) { KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // CprAcquireSerialSpinLock(devExt, &oldIrql); // Bit positions for MSR for RFC2217 Requirements // is the same for the CPR_UART_MSR_XXX defines. // DTR & DCD (0x80) // DSR (0x20) #define CPR_UART_MSR_DCTS 0x01 #define CPR_UART_MSR_DDSR 0x02 #define CPR_UART_MSR_TERI 0x04 #define CPR_UART_MSR_DDCD 0x08 #define CPR_UART_MSR_CTS 0x10 #define CPR_UART_MSR_DSR 0x20 #define CPR_UART_MSR_RI 0x40 #define CPR_UART_MSR_DCD 0x80 switch (devExt->DtrConnection) { case DTR_TO_DCD_DSR_ACTIVE: //default: MState |= CPR_UART_MSR_DSR; // Set DSR Active break; case DTR_TO_DCD_DSR_INACTIVE: MState &= ~CPR_UART_MSR_DSR; // Set DSR Inactive break; case DTR_TO_DSR_DCD_ACTIVE: if (MState & CPR_UART_MSR_DCD) MState |= CPR_UART_MSR_DSR; // Set DSR Active else MState &= ~CPR_UART_MSR_DSR; // Set DSR Inactive MState |= CPR_UART_MSR_DCD; // Set DCD Active break; case DTR_TO_DSR_DCD_INACTIVE: if (MState & CPR_UART_MSR_DCD) MState |= CPR_UART_MSR_DSR; // Set DSR Active else MState &= ~CPR_UART_MSR_DSR; // Set DSR Inactive MState &= ~CPR_UART_MSR_DCD; // Set DCD Inactive break; case DTR_TO_NONE: default: break; } devExt->Uart.Msr = MState; devExt->Uart.ModemStatusEvent = TRUE; CprUartCheckEvents(&devExt->Uart); // CprReleaseSerialSpinLock(devExt, oldIrql); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */ unsigned char CprRfc2217_GetModemState( PCPR_DEVICE_EXTENSION devExt ) { CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); return devExt->Uart.Msr; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } // This method is called with SerialLock held void SetLineState( PCPR_DEVICE_EXTENSION devExt, unsigned char LState ) { BOOLEAN lsrChanged = FALSE; CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"++"); LState &= ~CPR_UART_LSR_FIFOERR; // Everything except TN_LINESTATE_HOLDING_REG_EMPTY if ((devExt->Uart.Lsr & ~TN_LINESTATE_HOLDING_REG_EMPTY) != (LState & ~TN_LINESTATE_HOLDING_REG_EMPTY)) { devExt->Uart.LineStatusEvent = TRUE; lsrChanged = TRUE; } //if (LState & CPR_UART_LSR_FIFOERR) //{ // DbgPrint("\n===================\nSetLineState: FIFO ERROR\n====================\n\n"); //} devExt->Uart.Lsr = LState; devExt->TxEmptyVerifyPending = FALSE; devExt->TxEmptyRequested = FALSE; CheckLineState(devExt, LState); //if (CheckLineState(devExt, LState) || lsrChanged) //{ // CprUartCheckEvents(&devExt->Uart); //} CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"--"); } // CheckLineState is called with the Serial Lock held. BOOLEAN CheckLineState( PCPR_DEVICE_EXTENSION devExt, unsigned char LState ) { BOOLEAN retVal = FALSE; CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"++"); if (LState & TN_LINESTATE_HOLDING_REG_EMPTY) { // DAG-TX-EMPTY //CprDebugPrint8(devExt, DBG_IO, DBG_TRACE, // __FUNCTION__" Beg st %X, Pend %d, Comp %d, Len %d, Cur %p, QEmpty %d Req %d Idle %d", // LState, // devExt->PendingWriteCount, // devExt->WriteCompleteCount, // devExt->WriteLength, // devExt->WriteQueue.CurrentIrp, // IsListEmpty(&devExt->WriteQueue.IrpQueue), // devExt->TxEmptyRequested, // devExt->TxIdle // ); #ifdef CPR_DBG_PRINT DbgPrint( __FUNCTION__" Beg st %X, Pend %d, Len %d, Cur %p, QEmpty %d Req %d Idle %d\n", LState, devExt->PendingWriteCount, devExt->WriteLength, devExt->WriteQueue.CurrentIrp, IsListEmpty(&devExt->WriteQueue.IrpQueue), devExt->TxEmptyRequested, devExt->TxIdle ); #endif CprDebugPrint7(devExt, DBG_IO, DBG_TRACE, __FUNCTION__" Beg st %X, Pend %d, Len %d, Cur %p, QEmpty %d Req %d Idle %d", LState, devExt->PendingWriteCount, devExt->WriteLength, devExt->WriteQueue.CurrentIrp, IsListEmpty(&devExt->WriteQueue.IrpQueue), devExt->TxEmptyRequested, devExt->TxIdle ); //if ((devExt->WriteLength == 0) && IsListEmpty(&devExt->WriteQueue.IrpQueue)) //{ // if (devExt->WaitOnWrite || (devExt->WriteQueue.CurrentIrp == NULL)) // { // DAG-TX-EMPTY //CprDebugPrint(devExt, DBG_IO, DBG_TRACE, // __FUNCTION__" Pending %d Complete %d Result %d\n", // devExt->PendingWriteCount, devExt->WriteCompleteCount, // devExt->PendingWriteCount - devExt->WriteCompleteCount); //devExt->PendingWriteCount -= devExt->WriteCompleteCount; //devExt->PendingWriteCountTxEmpty -= devExt->WriteCompleteCount; //devExt->WriteCompleteCount = 0; // DAG-TX-EMPTY //if ((LONG)devExt->PendingWriteCount < 0) //{ if ((devExt->WriteIrpStatus != CURRENT_IRP_STATUS_QUEUED) && IsListEmpty(&devExt->WriteQueue.IrpQueue)) { devExt->PendingWriteCount = 0; //} // DAG-TX-EMPTY //if ((devExt->TxEmptyRequested == TRUE) && // //(LState & TN_LINESTATE_HOLDING_REG_EMPTY) && // (devExt->PendingWriteCountTxEmpty == 0)) // //(devExt->PendingWriteCount == 0)) devExt->TxEmptyRequested = FALSE; //devExt->Uart.TxEmptyEvent = TRUE; retVal = TRUE; devExt->TxWriteInProgress = FALSE; devExt->TxIdle = TRUE; #ifdef USE_WAIT_ON_WRITES if (devExt->WaitOnWrite && devExt->WriteQueue.CurrentIrp && devExt->WriteQueue.CurrentIrp->UserEvent) { KeSetEvent(devExt->WriteQueue.CurrentIrp->UserEvent, IO_NO_INCREMENT, FALSE); CprStartNext(&devExt->WriteQueue); } #endif //CprUartCheckEvents(&devExt->Uart); CprCheckForEmptyTransmitEvent(devExt); // DAG-TX-EMPTY //if (devExt->TxEmptyRequested == TRUE) //{ // devExt->TxEmptyRequested = FALSE; // //devExt->TxEmptyVerifyPending = FALSE; // devExt->Uart.TxEmptyEvent = TRUE; // retVal = TRUE; // devExt->TxWriteInProgress = FALSE; // devExt->TxIdle = TRUE; // if (devExt->WaitOnWrite && devExt->WriteQueue.CurrentIrp && devExt->WriteQueue.CurrentIrp->UserEvent) // { // KeSetEvent(devExt->WriteQueue.CurrentIrp->UserEvent, IO_NO_INCREMENT, FALSE); // CprStartNext(&devExt->WriteQueue); // } // CprUartCheckEvents(&devExt->Uart); //} //else //{ // if (deviceExtension->WriteReceived) // { // RequestLineState(devExt); // } // //else if ((devExt->TxEmptyRequested == FALSE) && // // (devExt->TxEmptyVerifyPending == FALSE) && // // (devExt->PendingWriteCount == 0)) // //{ // //CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__" Requesting TxEmpty"); // //devExt->TxEmptyRequested = TRUE; // //devExt->TxEmptyVerifyPending = TRUE; // //CprRfc2217_SendCPCByteCommand(devExt, TNCAS_NOTIFY_LINESTATE, 0); // //CprRfc2217_SendToNet(devExt, FALSE); // //} //} } else { devExt->TxEmptyRequested = FALSE; } // DAG-TX-EMPTY //CprDebugPrint8(devExt, DBG_IO, DBG_TRACE, // __FUNCTION__" End st %X, Pend %d, Comp %d, Len %d, Cur %p, QEmpty %d Req %d Idle %d", // LState, // devExt->PendingWriteCount, // devExt->WriteCompleteCount, // devExt->WriteLength, // devExt->WriteQueue.CurrentIrp, // IsListEmpty(&devExt->WriteQueue.IrpQueue), // devExt->TxEmptyRequested, // devExt->TxIdle // ); CprDebugPrint7(devExt, DBG_IO, DBG_TRACE, __FUNCTION__" End st %X, Pend %d, Len %d, Cur %p, QEmpty %d Req %d Idle %d", LState, devExt->PendingWriteCount, devExt->WriteLength, devExt->WriteQueue.CurrentIrp, IsListEmpty(&devExt->WriteQueue.IrpQueue), devExt->TxEmptyRequested, devExt->TxIdle ); //} //else //{ // devExt->TxEmptyRequested = FALSE; //} } else { devExt->TxEmptyRequested = FALSE; } CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return retVal; } void RequestLineState( PCPR_DEVICE_EXTENSION devExt ) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"++ ReqFlag %d PendFlag %d\n", devExt->TxEmptyRequested, devExt->TxEmptyVerifyPending); #endif CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"++ ReqFlag %d PendFlag %d", devExt->TxEmptyRequested, devExt->TxEmptyVerifyPending); //if ((devExt->TxEmptyRequested == FALSE) && // (devExt->TxEmptyVerifyPending == FALSE)) //{ CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__" Requesting Line State"); devExt->TxEmptyRequested = TRUE; devExt->TxEmptyVerifyPending = TRUE; CprRfc2217_SendCPCByteCommand(devExt, TNCAS_NOTIFY_LINESTATE, 0); CprRfc2217_SendToNet(devExt, FALSE); //} CprDebugPrint(devExt, DBG_IO, DBG_TRACE, __FUNCTION__"-- ReqFlag %d PendFlag %d", devExt->TxEmptyRequested, devExt->TxEmptyVerifyPending); } /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */ unsigned char CprRfc2217_GetLineState( PCPR_DEVICE_EXTENSION devExt ) { UCHAR Lsr; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); Lsr = devExt->Uart.Lsr; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return Lsr; } /* Set the serial port data size */ // This method is called with SerialLock held void SetPortDataSize( PCPR_DEVICE_EXTENSION devExt, unsigned char DataSize ) { unsigned char data = 0; unsigned char mask; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); mask = 0xff; switch (DataSize) { case 5: data = CPR_UART_LCR_5_DATA; mask = 0x1f; break; case 6: data = CPR_UART_LCR_6_DATA; mask = 0x3f; break; case 7: data = CPR_UART_LCR_7_DATA; mask = 0x7f; break; case 8: data = CPR_UART_LCR_8_DATA; break; default: return; } devExt->WmiCommData.BitsPerByte = DataSize; // CprAcquireSerialSpinLock(devExt, &oldIrql); devExt->LineControl = (UCHAR)((devExt->LineControl & CPR_UART_LCR_PARITY_MASK) | (devExt->LineControl & CPR_UART_LCR_STOP_MASK) | (devExt->LineControl & CPR_UART_LCR_BREAK) | data); devExt->DataMask = mask; CprUartWriteLCR(&devExt->Uart, devExt->LineControl); // CprReleaseSerialSpinLock(devExt, oldIrql); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Set the serial port parity */ // This method is called with SerialLock held void SetPortParity( PCPR_DEVICE_EXTENSION devExt, unsigned char Parity ) { unsigned char parity = 0; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // // Convert to Ones base. // switch (Parity+1) { case NO_PARITY: devExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; parity = CPR_UART_LCR_NONE_PARITY; break; case ODD_PARITY: devExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; parity = CPR_UART_LCR_ODD_PARITY; break; case EVEN_PARITY: devExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; parity = CPR_UART_LCR_EVEN_PARITY; break; case MARK_PARITY: devExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; parity = CPR_UART_LCR_MARK_PARITY; break; case SPACE_PARITY: devExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; parity = CPR_UART_LCR_SPACE_PARITY; break; default: return; } // CprAcquireSerialSpinLock(devExt, &oldIrql); devExt->LineControl = (UCHAR)((devExt->LineControl & CPR_UART_LCR_DATA_MASK) | (devExt->LineControl & CPR_UART_LCR_STOP_MASK) | (devExt->LineControl & CPR_UART_LCR_BREAK) | parity); CprUartWriteLCR(&devExt->Uart, devExt->LineControl); // CprReleaseSerialSpinLock(devExt, oldIrql); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Set the serial port stop bits size */ // This method is called with SerialLock held void SetPortStopSize( PCPR_DEVICE_EXTENSION devExt, unsigned char StopSize ) { unsigned char stop = 0; KIRQL oldIrql; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); switch (StopSize) { case 1: //STOP_BIT_1: devExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1; stop = CPR_UART_LCR_1_STOP; break; case 3: //STOP_BITS_1_5: devExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5; stop = CPR_UART_LCR_1_5_STOP; break; case 2: //STOP_BITS_2: devExt->WmiCommData.StopBits = SERIAL_WMI_STOP_2; stop = CPR_UART_LCR_2_STOP; break; default: return; } // CprAcquireSerialSpinLock(devExt, &oldIrql); devExt->LineControl = (UCHAR)((devExt->LineControl & CPR_UART_LCR_DATA_MASK) | (devExt->LineControl & CPR_UART_LCR_PARITY_MASK) | (devExt->LineControl & CPR_UART_LCR_BREAK) | stop); CprUartWriteLCR(&devExt->Uart, devExt->LineControl); // CprReleaseSerialSpinLock(devExt, oldIrql); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Set the port flow control and DTR and RTS status */ void SetPortFlowControl( PCPR_DEVICE_EXTENSION devExt, unsigned char How) { //struct termios PortSettings; //int MLines; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); ///* Gets the base status from the port */ //tcgetattr(PortFd,&PortSettings); //ioctl(PortFd,TIOCMGET,&MLines); ///* Check which settings to change */ //switch (How) //{ // case 1: /* No Flow Control (outbound/both) */ // PortSettings.c_iflag = PortSettings.c_iflag & ~IXON; // PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF; // PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS; // break; // // case 2: /* XON/XOFF Flow Control (outbound/both) */ // PortSettings.c_iflag = PortSettings.c_iflag | IXON; // PortSettings.c_iflag = PortSettings.c_iflag | IXOFF; // PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS; // break; // // case 3: /* HARDWARE Flow Control (outbound/both) */ // PortSettings.c_iflag = PortSettings.c_iflag & ~IXON; // PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF; // PortSettings.c_cflag = PortSettings.c_cflag | CRTSCTS; // break; // // case 5: /* BREAK State ON */ // tcsendbreak(PortFd,1); // BreakSignaled = True; // break; // // case 6: /* BREAK State OFF */ // /* Should not send another break */ // /* tcsendbreak(PortFd,0); */ // BreakSignaled = False; // break; // // case 8: /* DTR Signal State ON */ // MLines = MLines | TIOCM_DTR; // break; // // case 9: /* DTR Signal State OFF */ // MLines = MLines & ~TIOCM_DTR; // break; // // case 11: /* RTS Signal State ON */ // MLines = MLines | TIOCM_RTS; // break; // // case 12: /* RTS Signal State OFF */ // MLines = MLines & ~TIOCM_RTS; // break; // /* INBOUND FLOW CONTROL is ignored */ // // case 14: /* No Flow Control (inbound) */ // case 15: /* XON/XOFF Flow Control (inbound) */ // case 16: /* HARDWARE Flow Control (inbound) */ // //LogMsg(LOG_WARNING,"Inbound flow control ignored."); // break; // default: // //LogMsg(LOG_WARNING,"Requested unsupported flow control."); // break; //} //tcsetattr(PortFd,TCSADRAIN,&PortSettings); //ioctl(PortFd,TIOCMSET,&MLines); CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Set the serial port speed */ void SetPortSpeed( PCPR_DEVICE_EXTENSION devExt, unsigned long BaudRate ) { CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); devExt->BaudRate = BaudRate; CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* initialize Telnet State Machine */ void InitTelnetStateMachine(CPR_TELNET_STATE tnstate[]) { RtlZeroMemory(tnstate, sizeof(CPR_TELNET_STATE) * MAX_TELNET_COMMANDS); } /* Send the signature Sig to the client */ void SendSignature( PCPR_DEVICE_EXTENSION devExt, char * Sig ) { CPR_BUFFER_TYPE * B = &devExt->ToNetBuf; AddToBuffer(B, TNIAC); AddToBuffer(B, TNSB); AddToBuffer(B, TNCOM_PORT_OPTION); AddToBuffer(B, TNCAS_SIGNATURE); SendStr(devExt ,Sig); AddToBuffer(B, TNIAC); AddToBuffer(B, TNSE); } void CprRfc2217_RequestSignature( PCPR_DEVICE_EXTENSION devExt ) { SendSignature(devExt, ""); } void CprRfc2217_SendOurSignature( PCPR_DEVICE_EXTENSION devExt ) { char SigStr[TmpStrLen]; char Msg[CPR_EVENT_MSG_SIZE]; RtlStringCchPrintfA(SigStr, sizeof(SigStr), "CPR %s", CPR_DRVR_VERSION); SendSignature(devExt, SigStr); RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: Signature '%s'.", SigStr); LogMsg(devExt, Msg); } /* Write a char to socket performing IAC escaping */ void EscWriteChar( PCPR_DEVICE_EXTENSION devExt, unsigned char C ) { CPR_BUFFER_TYPE * B = &devExt->ToNetBuf; if (C == TNIAC) AddToBuffer(B,C); else if (C != 0x0A && !devExt->TelnetState[TN_TRANSMIT_BINARY].is_will && devExt->LastToNet == 0x0D) AddToBuffer(B,0x00); AddToBuffer(B,C); /* Set last sent byte */ devExt->LastToNet = C; } /* Redirect char C to Device checking for IAC escape sequences */ void CprRfc2217_EscRedirectChar( PCPR_DEVICE_EXTENSION devExt, unsigned char C ) { //CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); /* Check the IAC escape status */ switch( devExt->IACEscape ) { /* Normal status */ case IACNormal: if (C == TNIAC) devExt->IACEscape = IACReceived; else if (!devExt->TelnetState[TN_TRANSMIT_BINARY].is_do && C == 0x00 && devExt->LastFromNet == 0x0D) { /* Swallow the NUL after a CR if not receiving BINARY */ break; } else { CprSerialPutChar(devExt, C & devExt->DataMask); } break; /* IAC previously received */ case IACReceived: if (C == TNIAC) { CprSerialPutChar(devExt, C & devExt->DataMask); devExt->IACEscape = IACNormal; } else if (C == TNEND) { devExt->IACEscape = IACNormal; } else if (C == TNSE) { // This will finish up an invalid // RFC2217 command. devExt->IACEscape = IACNormal; } else { devExt->IACCommand[0] = TNIAC; devExt->IACCommand[1] = C; devExt->IACPos = 2; devExt->IACEscape = IACComReceiving; devExt->IACSigEscape = IACNormal; } break; /* IAC Command reception */ case IACComReceiving: /* Telnet suboption, could be only CPC */ if (devExt->IACCommand[1] == TNSB) { /* Get the suboption signature */ if (devExt->IACPos < 4) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } else { /* Check which suboption we are dealing with */ switch (devExt->IACCommand[3]) { case TNCAS_SET_LINESTATE_MASK: case TNCAS_SET_MODEMSTATE_MASK: devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 6) { // Will only get back if there is a loopback plug devExt->Rfc2217OwnSignature = TRUE; devExt->Rfc2217Enabled = FALSE; //HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; case TNCAS_SIGNATURE: switch (devExt->IACSigEscape) { case IACNormal: if (C == TNIAC) devExt->IACSigEscape = IACReceived; else if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } break; case IACComReceiving: devExt->IACSigEscape = IACNormal; break; case IACReceived: if (C == TNIAC) { if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } devExt->IACSigEscape = IACNormal; } else { if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = TNIAC; devExt->IACPos++; } if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } // Will only get back if there is a loopback plug devExt->Rfc2217OwnSignature = TRUE; devExt->Rfc2217Enabled = FALSE; //HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; } break; /* Signature, which needs further escaping */ case TNASC_SIGNATURE: switch (devExt->IACSigEscape) { case IACNormal: if (C == TNIAC) devExt->IACSigEscape = IACReceived; else if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } break; case IACComReceiving: devExt->IACSigEscape = IACNormal; break; case IACReceived: if (C == TNIAC) { if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } devExt->IACSigEscape = IACNormal; } else { if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = TNIAC; devExt->IACPos++; } if (devExt->IACPos < TmpStrLen) { devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; } HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; } break; /* Flow control command */ case TNASC_FLOWCONTROL_SUSPEND: case TNASC_FLOWCONTROL_RESUME: devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 6) { HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; #ifdef BUFFER_STATE case TNASC_NOTIFY_BUFFERSTATE: devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 14) { HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; #endif /* Set baudrate */ case TNASC_SET_BAUDRATE: devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 10) { HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } break; /* Normal CPC command with single byte parameter */ default: devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 7) { HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } else if ((devExt->IACPos == 6) && (C == TNSE)) { // Error: End Came too early, no value was sent devExt->IACEscape = IACNormal; } break; } } } else { /* Normal 3 byte IAC option */ devExt->IACCommand[devExt->IACPos] = C; devExt->IACPos++; if (devExt->IACPos == 3) { HandleIACCommand(devExt); devExt->IACEscape = IACNormal; } } break; default: break; } /* Set last received byte */ devExt->LastFromNet = C; //CprDebugPrint(devExt, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); } /* Send the specific telnet option to SockFd using Command as command */ void SendTelnetOption(CPR_BUFFER_TYPE * B, unsigned char Command, char Option) { unsigned char IAC = TNIAC; AddToBuffer(B,IAC); AddToBuffer(B,Command); AddToBuffer(B,Option); } /* Send a string to SockFd performing IAC escaping */ void SendStr( PCPR_DEVICE_EXTENSION devExt, char * Str ) { size_t I; size_t L; L = strlen(Str); for (I = 0; I < L;I++) EscWriteChar(devExt, (unsigned char) Str[I]); } /* Send the baud rate BR to Buffer */ void CprRfc2217_SendBaudRate( PCPR_DEVICE_EXTENSION devExt, unsigned long int BR ) { unsigned char *p; unsigned long int NBR; int i; CPR_BUFFER_TYPE *B = &devExt->ToNetBuf; char Msg[CPR_EVENT_MSG_SIZE]; NBR = htonl(BR); AddToBuffer(B,TNIAC); AddToBuffer(B,TNSB); AddToBuffer(B,TNCOM_PORT_OPTION); AddToBuffer(B,TNCAS_SET_BAUDRATE); p = (unsigned char *) &NBR; for (i = 0;i < (int) sizeof(NBR);i++) { AddToBuffer(B, p[i]); // EscWriteChar(devExt, p[i]); } AddToBuffer(B,TNIAC); AddToBuffer(B,TNSE); RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: baud rate change: %d", BR); LogMsg(devExt, Msg); } /* Send the flow control command Command */ void SendCPCFlowCommand( PCPR_DEVICE_EXTENSION devExt, unsigned char Command ) { CPR_BUFFER_TYPE *B = &devExt->ToNetBuf; AddToBuffer(B,TNIAC); AddToBuffer(B,TNSB); AddToBuffer(B,TNCOM_PORT_OPTION); AddToBuffer(B,Command); AddToBuffer(B,TNIAC); AddToBuffer(B,TNSE); // Need to Send Flow control and place the LogMsg commands below // there also. if (Command == TNCAS_FLOWCONTROL_SUSPEND) LogMsg(devExt, "CPR->Device: flow control suspend command."); else LogMsg(devExt, "CPR->Device: flow control resume command."); } void LogRFC2217SendCommand( PCPR_DEVICE_EXTENSION devExt, unsigned char Command, unsigned char Parm ) { char Msg[CPR_EVENT_MSG_SIZE]; Msg[0] = '\0'; switch (Command) { case TNCAS_SET_BAUDRATE: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: baud rate: %d", Parm); break; case TNCAS_SET_DATASIZE: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: data size: %d", Parm); break; case TNCAS_SET_PARITY: switch (Parm) { case 0: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity request", Parm); break; case 1: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity: NONE"); break; case 2: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity: ODD"); break; case 3: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity: EVEN"); break; case 4: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity: MARK"); break; default: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: parity: UNKNOWN: %d", Parm); break; } break; case TNCAS_SET_STOPSIZE: switch (Parm) { case 0: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: stop bit size request", Parm); break; case 1: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: stop bit size: 1"); break; case 2: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: stop bit size: 2"); break; case 3: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: stop bit size: 1.5"); break; default: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: stop bit size: UNKNOWN: %d", Parm); break; } break; case TNCAS_SET_CONTROL: switch (Parm) { case TN_CONTROL_FLOW_REQUEST: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: flow control request"); break; case TN_CONTROL_FLOW_NONE: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: flow control: NONE"); break; case TN_CONTROL_FLOW_XON_XOFF: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: flow control: XON/XOFF"); break; case TN_CONTROL_FLOW_HARDWARE: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: flow control: HARDWARE"); break; case TN_CONTROL_BREAK_REQUEST: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: break request"); break; case TN_CONTROL_BREAK_ON: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: break on"); break; case TN_CONTROL_BREAK_OFF: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: break off"); break; case TN_CONTROL_DTR_REQUEST: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: DTR request"); break; case TN_CONTROL_DTR_ON: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: DTR ON"); break; case TN_CONTROL_DTR_OFF: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: DTR OFF"); break; case TN_CONTROL_RTS_REQUEST: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: RTS request"); break; case TN_CONTROL_RTS_ON: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: RTS ON"); break; case TN_CONTROL_RTS_OFF: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: RTS OFF"); break; // The remaining are inboung flow control: we do not send them. //case TN_CONTROL_FLOW_CONTROL_REQUEST: //case TN_CONTROL_FLOW_CONTROL_NONE: //case TN_CONTROL_FLOW_CONTROL_XON_XOFF: //case TN_CONTROL_FLOW_CONTROL_HARDWARE: //case TN_CONTROL_FLOW_CONTROL_DCD: //case TN_CONTROL_FLOW_CONTROL_DTR: //case TN_CONTROL_FLOW_CONTROL_DSR: } break; case TNCAS_NOTIFY_LINESTATE: if (Parm == 0) RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: line state request"); else RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: line state: 0x%X", Parm); break; case TNCAS_NOTIFY_MODEMSTATE: if (Parm == 0) RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: modem state request"); else RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: modem state: 0x%X", Parm); break; case TNCAS_SET_LINESTATE_MASK: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: line state mask: 0x%X", Parm); break; case TNCAS_SET_MODEMSTATE_MASK: RtlStringCchPrintfA(Msg, sizeof(Msg), "CPR->Device: modem state mask: 0x%X", Parm); break; } if (Msg[0] != '\0') LogMsg(devExt, Msg); } /* Send the CPC command Command using Parm as parameter */ void CprRfc2217_SendCPCByteCommand( PCPR_DEVICE_EXTENSION devExt, unsigned char Command, unsigned char Parm ) { CPR_BUFFER_TYPE *B = &devExt->ToNetBuf; AddToBuffer(B,TNIAC); AddToBuffer(B,TNSB); AddToBuffer(B,TNCOM_PORT_OPTION); AddToBuffer(B,Command); AddToBuffer(B,Parm); AddToBuffer(B,TNIAC); AddToBuffer(B,TNSE); LogRFC2217SendCommand(devExt, Command, Parm); } /* Handling of COM Port Control specific commands */ void HandleCPCCommand( PCPR_DEVICE_EXTENSION devExt ) { char SigStr[TmpStrLen]; unsigned long int BaudRate; unsigned char DataSize; unsigned char Parity; unsigned char StopSize; unsigned char FlowControl; unsigned char *Command = devExt->IACCommand; char Msg[CPR_EVENT_MSG_SIZE]; size_t CSize = devExt->IACPos; // This code was designed to be an Access Server // CPR is actually a client. // The code that is commented out is specific // to an Access Server. // NOTIFY-MODEMSTATE and NOTIFY-LINESTATE // was added because these are commands a client // would respond to. // // Check which command has been requested // switch (Command[3]) { /* Signature */ case TNASC_SIGNATURE: if (CSize == 6) { /* Void signature, client is asking for our signature */ CprRfc2217_SendOurSignature(devExt); //DbgPrint("Device->CPR Request for signature\n"); LogMsg(devExt, "Device->CPR Request for signature."); } else { /* Received Access Server signature */ RtlStringCchCopyNA(SigStr, sizeof(SigStr), (char *) &Command[4], CSize - 6); RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR Signature '%s'.", SigStr); LogMsg(devExt, Msg); } break; /* Suspend output to the client */ case TNASC_FLOWCONTROL_SUSPEND: LogMsg(devExt, "Device->CPR Flow control suspend requested."); devExt->InputFlow = False; break; /* Resume output to the client */ case TNASC_FLOWCONTROL_RESUME: LogMsg(devExt, "Device->CPR Flow control resume requested."); devExt->InputFlow = True; break; case TNASC_NOTIFY_MODEMSTATE: LogModemState(devExt, Command[4]); SetModemState(devExt, Command[4]); break; case TNASC_NOTIFY_LINESTATE: LogLineState(devExt, Command[4]); SetLineState(devExt, Command[4]); break; #ifdef BUFFER_STATE case TNASC_NOTIFY_BUFFERSTATE: DbgPrint("TNASC_NOTIFY_BUFFERSTATE: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", Command[0], Command[1], Command[2], Command[3], Command[4], Command[5], Command[6], Command[7], Command[8], Command[9], Command[10], Command[11], Command[12], Command[13]); devExt->BufferStatePending = FALSE; break; #endif /* Set serial baud rate */ case TNASC_SET_BAUDRATE: /* Retrieve the baud rate which is in network order */ BaudRate = ntohl(*((unsigned long int *) &Command[4])); if (BaudRate == 0) { /* Server is asking for current baud rate */ LogMsg(devExt, "Device->CPR request for baud rate."); BaudRate = CprRfc2217_GetPortSpeed(devExt); CprRfc2217_SendBaudRate(devExt, BaudRate); } else { /* Change the baud rate */ //sprintf(LogStr,"Port baud rate change to %lu requested.",BaudRate); //LogMsg(LOG_DEBUG,LogStr); //SetPortSpeed(devExt, BaudRate); } RtlStringCchPrintfA(Msg, sizeof(Msg), "Current port baud rate: %lu",BaudRate); LogMsg(devExt, Msg); break; /* Set serial data size */ case TNASC_SET_DATASIZE: DataSize = CprRfc2217_GetPortDataSize(devExt); if (Command[4] == 0) { /* Client is asking for current data size */ LogMsg(devExt,"Device->CPR request for data size."); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_DATASIZE, DataSize); } else { /* Set the data size */ //sprintf(LogStr,"Port data size change to %u requested.", // (unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); //SetPortDataSize(devExt, Command[4]); } //CprRfc2217_SendCPCByteCommand(devExt, SockB, TNASC_SET_DATASIZE, devExt->bau DataSize); RtlStringCchPrintfA(Msg, sizeof(Msg), "Current port data size: %u",(unsigned int) DataSize); LogMsg(devExt, Msg); break; /* Set the serial parity */ case TNASC_SET_PARITY: Parity = CprRfc2217_GetPortParity(devExt); if (Command[4] == 0) { /* Client is asking for current parity */ LogMsg(devExt,"Device->CPR request for parity."); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_PARITY, Parity); } else { /* Set the parity */ //sprintf(LogStr,"Port parity change to %u requested", // (unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); //SetPortParity(devExt, Command[4]); } RtlStringCchPrintfA(Msg, sizeof(Msg), "Current port parity: %u",(unsigned int) Parity); LogMsg(devExt, Msg); break; /* Set the serial stop size */ case TNASC_SET_STOPSIZE: StopSize = CprRfc2217_GetPortStopSize(devExt); if (Command[4] == 0) { /* Client is asking for current stop size */ LogMsg(devExt,"Device->CPR request for stop size."); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_STOPSIZE, StopSize); } else { /* Set the stop size */ //sprintf(LogStr,"Port stop size change to %u requested.", // (unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); //SetPortStopSize(devExt, Command[4]); } RtlStringCchPrintfA(Msg, sizeof(Msg), "Current port stop size: %u",(unsigned int) StopSize); LogMsg(devExt, Msg); break; /* Flow control and DTR/RTS handling */ case TNCAS_SET_CONTROL: //switch (Command[4]) //{ // case 0: // case 4: // case 7: // case 10: // case 13: // /* Client is asking for current flow control or DTR/RTS status */ // //LogMsg(LOG_DEBUG,"Flow control notification requested."); // FlowControl = CprRfc2217_GetPortFlowControl(devExt, Command[4]); // CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_CONTROL, FlowControl); // //sprintf(LogStr,"Port flow control: %u",(unsigned int) FlowControl); // //LogMsg(LOG_DEBUG,LogStr); // break; // case 5: // /* Break command */ // //tcsendbreak(PortFd,1); // devExt->BreakSignaled = True; // //LogMsg(LOG_DEBUG,"Break Signal ON."); // CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_CONTROL, Command[4]); // break; // case 6: // devExt->BreakSignaled = False; // //LogMsg(LOG_DEBUG,"Break Signal OFF."); // CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_CONTROL, Command[4]); // break; // default: // /* Set the flow control */ // //sprintf(LogStr,"Port flow control change to %u requested.",(unsigned int) Command[4]); // //LogMsg(LOG_DEBUG,LogStr); // SetPortFlowControl(devExt, Command[4]); // /* Flow control status confirmation */ // //if (CiscoIOSCompatible && Command[4] >= 13 && Command[4] <=16) // //{ // // /* INBOUND not supported separately. // // Following the behavior of Cisco ISO 11.3 // // */ // // FlowControl = 0; // //} // //else // //{ // /* Return the actual port flow control settings */ // FlowControl = CprRfc2217_GetPortFlowControl(devExt, 0); // //} // CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_CONTROL, FlowControl); // //sprintf(LogStr,"Port flow control: %u",(unsigned int) FlowControl); // //LogMsg(LOG_DEBUG,LogStr); // break; //} break; //case TNCAS_SET_LINESTATE_MASK: //case TNCAS_SET_MODEMSTATE_MASK: //case TNCAS_SIGNATURE: // // Probably received via loopback // // so fail it. // devExt->Rfc2217OwnSignature = TRUE; // devExt->Rfc2217Enabled = FALSE; // break; #ifdef ACCESS_SERVER /* Set the line state mask */ case TNCAS_SET_LINESTATE_MASK: //sprintf(LogStr,"Line state set to %u",(unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); /* Only break notification supported */ devExt->LineStateMask = Command[4] & (unsigned char) 16; CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_LINESTATE_MASK, devExt->LineStateMask); break; /* Set the modem state mask */ case TNCAS_SET_MODEMSTATE_MASK: //sprintf(LogStr,"Modem state mask set to %u",(unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); devExt->ModemStateMask = Command[4]; CprRfc2217_SendCPCByteCommand(devExt, TNASC_SET_MODEMSTATE_MASK, devExt->ModemStateMask); break; /* Port flush requested */ case TNCAS_PURGE_DATA: //sprintf(LogStr,"Port flush %u requested.",(unsigned int) Command[4]); //LogMsg(LOG_DEBUG,LogStr); //switch (Command[4]) //{ // case 1: /* Inbound flush */ // tcflush(PortFd,TCIFLUSH); // break; // case 2: /* Outbound flush */ // tcflush(PortFd,TCOFLUSH); // break; // case 3: /* Inbound/outbound flush */ // tcflush(PortFd,TCIOFLUSH); // break; //} CprRfc2217_SendCPCByteCommand(devExt, TNASC_PURGE_DATA, Command[4]); break; #endif /* Unknown request */ default: RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR: Unhandled request %u", (unsigned int) Command[3]); LogMsg(devExt, Msg); break; } } /* Common telnet IAC commands handling */ void HandleIACCommand( PCPR_DEVICE_EXTENSION devExt ) { unsigned char *Command = devExt->IACCommand; char Msg[CPR_EVENT_MSG_SIZE]; /* Check which command */ switch(Command[1]) { /* Suboptions */ case TNSB: if (!(devExt->TelnetState[Command[2]].is_will || devExt->TelnetState[Command[2]].is_do)) break; switch (Command[2]) { /* RFC 2217 COM Port Control Protocol option */ case TNCOM_PORT_OPTION: HandleCPCCommand(devExt); break; default: RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR Unknown suboption: %u", (unsigned int) Command[2]); LogMsg(devExt, Msg); break; } break; /* Requests for options */ case TNWILL: switch (Command[2]) { /* COM Port Control Option */ case TNCOM_PORT_OPTION: LogMsg(devExt, "Device->CPR Telnet COM Port Control Enabled (WILL)."); if (devExt->Rfc2217OwnSignature == FALSE) { devExt->Rfc2217Enabled = True; devExt->Rfc2217WaitStatus = STATUS_SUCCESS; KeSetEvent(&devExt->Rfc2217Event, IO_NO_INCREMENT, FALSE); if (!devExt->TelnetState[Command[2]].sent_do && !devExt->TelnetState[Command[2]].is_do) { SendTelnetOption(&devExt->ToNetBuf, TNDO, Command[2]); } devExt->TelnetState[Command[2]].is_do = 1; } break; /* Telnet Binary mode */ case TN_TRANSMIT_BINARY: LogMsg(devExt, "Device->CPR Telnet Binary Transfer Enabled (WILL)."); if (!devExt->TelnetState[Command[2]].sent_do && !devExt->TelnetState[Command[2]].is_do) { SendTelnetOption(&devExt->ToNetBuf, TNDO, Command[2]); } devExt->TelnetState[Command[2]].is_do = 1; break; /* Echo request not handled */ case TN_ECHO: LogMsg(devExt, "Device->CPR: Rejecting Telnet Echo Option (WILL)."); if (!devExt->TelnetState[Command[2]].sent_do && !devExt->TelnetState[Command[2]].is_do) { //SendTelnetOption(&devExt->ToNetBuf, TNDO, Command[2]); SendTelnetOption(&devExt->ToNetBuf, TNDONT, Command[2]); } devExt->TelnetState[Command[2]].is_do = 1; break; /* No go ahead needed */ case TN_SUPPRESS_GO_AHEAD: LogMsg(devExt, "Device->CPR Suppressing Go Ahead characters (WILL)."); if (!devExt->TelnetState[Command[2]].sent_do && !devExt->TelnetState[Command[2]].is_do) { SendTelnetOption(&devExt->ToNetBuf, TNDO, Command[2]); } devExt->TelnetState[Command[2]].is_do = 1; break; /* Reject everything else */ default: RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR: Rejecting option WILL: %u", (unsigned int) Command[2]); LogMsg(devExt, Msg); SendTelnetOption(&devExt->ToNetBuf, TNDONT, Command[2]); devExt->TelnetState[Command[2]].is_do = 0; break; } devExt->TelnetState[Command[2]].sent_do = 0; devExt->TelnetState[Command[2]].sent_dont = 0; break; /* Confirmations for options */ case TNDO: switch (Command[2]) { /* COM Port Control Option */ case TNCOM_PORT_OPTION: LogMsg(devExt, "Device->CPR Telnet COM Port Control Enabled (DO)."); if (devExt->Rfc2217OwnSignature == FALSE) { devExt->Rfc2217Enabled = True; devExt->Rfc2217WaitStatus = STATUS_SUCCESS; KeSetEvent(&devExt->Rfc2217Event, IO_NO_INCREMENT, FALSE); if (!devExt->TelnetState[Command[2]].sent_will && !devExt->TelnetState[Command[2]].is_will) { SendTelnetOption(&devExt->ToNetBuf, TNWILL, Command[2]); } devExt->TelnetState[Command[2]].is_will = 1; } break; /* Telnet Binary mode */ case TN_TRANSMIT_BINARY: LogMsg(devExt, "Device->CPR Telnet Binary Transfer Enabled (DO)."); if (!devExt->TelnetState[Command[2]].sent_will && !devExt->TelnetState[Command[2]].is_will) { SendTelnetOption(&devExt->ToNetBuf, TNWILL, Command[2]); } devExt->TelnetState[Command[2]].is_will = 1; break; /* Echo request handled. The modem will echo for the user. */ case TN_ECHO: LogMsg(devExt, "Device->CPR Telnet Echo Option (DO) rejection."); if (!devExt->TelnetState[Command[2]].sent_will && !devExt->TelnetState[Command[2]].is_will) { // SendTelnetOption(&devExt->ToNetBuf, TNWILL, Command[2]); SendTelnetOption(&devExt->ToNetBuf, TNWONT, Command[2]); } devExt->TelnetState[Command[2]].is_will = 1; break; /* No go ahead needed */ case TN_SUPPRESS_GO_AHEAD: LogMsg(devExt, "Device->CPR Suppressing Go Ahead characters (DO)."); if (!devExt->TelnetState[Command[2]].sent_will && !devExt->TelnetState[Command[2]].is_will) { SendTelnetOption(&devExt->ToNetBuf, TNWILL, Command[2]); } devExt->TelnetState[Command[2]].is_will = 1; break; /* Reject everything else */ default: RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR: Rejecting option DO: %u",(unsigned int) Command[2]); LogMsg(devExt, Msg); SendTelnetOption(&devExt->ToNetBuf, TNWONT, Command[2]); devExt->TelnetState[Command[2]].is_will = 0; break; } devExt->TelnetState[Command[2]].sent_will = 0; devExt->TelnetState[Command[2]].sent_wont = 0; break; /* Notifications of rejections for options */ case TNDONT: RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR rejection for option (DONT): %u",(unsigned int) Command[2]); LogMsg(devExt, Msg); if (devExt->TelnetState[Command[2]].is_will) { SendTelnetOption(&devExt->ToNetBuf, TNWONT, Command[2]); devExt->TelnetState[Command[2]].is_will = 0; } devExt->TelnetState[Command[2]].sent_will = 0; devExt->TelnetState[Command[2]].sent_wont = 0; break; case TNWONT: if (Command[2] == TNCOM_PORT_OPTION) { LogMsg(devExt, "Client doesn't support Telnet COM Port " "Protocol Option (RFC 2217), trying to serve anyway."); } else { RtlStringCchPrintfA(Msg, sizeof(Msg), "Device->CPR rejection for option: %u",(unsigned int) Command[2]); LogMsg(devExt, Msg); } if (devExt->TelnetState[Command[2]].is_do) { SendTelnetOption(&devExt->ToNetBuf, TNDONT, Command[2]); devExt->TelnetState[Command[2]].is_do = 0; } devExt->TelnetState[Command[2]].sent_do = 0; devExt->TelnetState[Command[2]].sent_dont = 0; break; } } /* Write a buffer to SockFd with IAC escaping */ void EscWriteBuffer(CPR_BUFFER_TYPE * B, unsigned char * Buffer, unsigned int BSize) { unsigned int I; for (I = 0;I < BSize;I++) { if (Buffer[I] == TNIAC) AddToBuffer(B,TNIAC); AddToBuffer(B,Buffer[I]); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprRfc2217_Negotiate // Negotiate with the remote device server // // Arguments: // IN devExt // device extension // // Return Value: // NTSTATUS // // Comment: // This method is NOT called with SerialLock held // This method is called on a DPC // NTSTATUS CprRfc2217_Negotiate( PCPR_DEVICE_EXTENSION devExt ) { NTSTATUS status; LARGE_INTEGER timeout; char Msg[CPR_EVENT_MSG_SIZE]; KIRQL oldIrql; //UCHAR DataSize; //UCHAR Parity; //UCHAR StopSize; #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"++\n"); #endif CprDebugPrint(devExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++"); // // Set up the buffer to send to the device server // //DbgPrint("in CprRfc2217_Negotiate\n"); CprAcquireSerialSpinLock(devExt, &oldIrql); CprRfc2217_SendOurSignature(devExt); SendTelnetOption(&devExt->ToNetBuf, TNWILL, TN_TRANSMIT_BINARY); devExt->TelnetState[TN_TRANSMIT_BINARY].sent_will = 1; SendTelnetOption(&devExt->ToNetBuf,TNDO, TN_TRANSMIT_BINARY); devExt->TelnetState[TN_TRANSMIT_BINARY].sent_do = 1; SendTelnetOption(&devExt->ToNetBuf,TNWONT, TN_ECHO); devExt->TelnetState[TN_ECHO].sent_wont = 1; SendTelnetOption(&devExt->ToNetBuf,TNDONT, TN_ECHO); devExt->TelnetState[TN_ECHO].sent_dont = 1; SendTelnetOption(&devExt->ToNetBuf,TNWILL, TN_SUPPRESS_GO_AHEAD); devExt->TelnetState[TN_SUPPRESS_GO_AHEAD].sent_will = 1; SendTelnetOption(&devExt->ToNetBuf,TNDO, TN_SUPPRESS_GO_AHEAD); devExt->TelnetState[TN_SUPPRESS_GO_AHEAD].sent_do = 1; SendTelnetOption(&devExt->ToNetBuf,TNDO, TNCOM_PORT_OPTION); devExt->TelnetState[TNCOM_PORT_OPTION].sent_do = 1; //LogMsg(devExt, "Sent: Will & Do Binary, Won't & Don't Echo, Will & Do Suppress_Go_Ahead, Do ComPort_Option"); LogMsg(devExt, "CPR->Device: Will & Do Binary, Will & Do Suppress_Go_Ahead, Do ComPort_Option"); KeClearEvent(&devExt->Rfc2217Event); // Send the negotiation parameters to the device server status = CprRfc2217_SendToNet(devExt, TRUE); if (status == STATUS_SUCCESS) { // Camp out waiting for negotiation reply // Use Connection timeout as the timeout value. (CnTmo) // If no negotiations, then fail connection. // Need to wait for devExt->Rfc2217Enabled to be set. // devExt->Rfc2217WaitStatus = STATUS_SUCCESS; KeSetTimer(&devExt->Rfc2217Timer, devExt->Rfc2217Timeout, &devExt->Rfc2217TimeoutDpc); //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprReleaseSerialSpinLockFromDpcLevel(devExt); CprReleaseSerialSpinLock(devExt, oldIrql); KeWaitForSingleObject(&devExt->Rfc2217Event, Executive, KernelMode, FALSE, NULL); // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(devExt); CprAcquireSerialSpinLock(devExt, &oldIrql); status = devExt->Rfc2217WaitStatus; KeCancelTimer(&devExt->Rfc2217Timer); if ((devExt->Rfc2217Enabled == FALSE) || (devExt->Rfc2217OwnSignature == TRUE)) { status = STATUS_PORT_CONNECTION_REFUSED; } } CprReleaseSerialSpinLock(devExt, oldIrql); #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"--. status 0x%08X\n", status); #endif CprDebugPrint1(devExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. status 0x%08X", status); return status; } NTSTATUS CprRfc2217_SendPortSettings( PCPR_DEVICE_EXTENSION devExt ) { char Msg[CPR_EVENT_MSG_SIZE]; UCHAR DataSize; UCHAR Parity; UCHAR StopSize; // Line State Mask CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_LINESTATE_MASK, LineStateECMask); // Modem State Mask CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_MODEMSTATE_MASK, ModemStateECMask); // Baud Rate CprRfc2217_SendBaudRate(devExt, devExt->BaudRate); // Data Size DataSize = CprRfc2217_GetPortDataSize(devExt); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_DATASIZE, DataSize); // Parity Parity = CprRfc2217_GetPortParity(devExt); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_PARITY, Parity); // Stop Bits StopSize = CprRfc2217_GetPortStopSize(devExt); CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_STOPSIZE, StopSize); // Flow Control - Default to no flow control CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_FLOW_NONE); //CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_FLOW_CONTROL_NONE); return CprRfc2217_SendToNet(devExt, TRUE); } NTSTATUS CprRfc2217_SendToNet( PCPR_DEVICE_EXTENSION devExt, BOOLEAN Wait ) { int length; unsigned char *buffer; NTSTATUS status; if (devExt->IsDeviceEnabled || devExt->IsDeviceNegotiating) { status = CprRfc2217_GetBuffer(&devExt->ToNetBuf, &buffer, &length); if (buffer != NULL) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" Buf %p, Len %d, Rd %d, Wr %d\n", buffer, length, devExt->ToNetBuf.RdPos, devExt->ToNetBuf.WrPos); #endif #ifdef CPR_DBG_PRINT CprDumpBuffer(__FUNCTION__, buffer, length); #endif // Send RFC 2217 commands to the device server on the network. //InitBuffer(&devExt->ToNetBuf); //devExt->ToNetBuf.RdPos = devExt->ToNetBuf.WrPos = 0; status = CprUartWriteDirect(&devExt->Uart, buffer, length, Wait, TRUE); #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" status 0x%08X\n", status); #endif } } else { status = !STATUS_SUCCESS; } return status; } VOID CprRfc2217Timeout( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint(deviceExtension, DBG_IO, DBG_VERB, __FUNCTION__"++"); // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); deviceExtension->Rfc2217WaitStatus = STATUS_IO_TIMEOUT; KeSetEvent(&deviceExtension->Rfc2217Event, IO_NO_INCREMENT, FALSE); KeSetEvent(&deviceExtension->Rfc2217SendEvent, IO_NO_INCREMENT, FALSE); // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprDebugPrint(deviceExtension, DBG_IO, DBG_VERB, __FUNCTION__"--"); return; } NTSTATUS CprRfc2217_GetBuffer( CPR_BUFFER_TYPE *ToNetBuf, unsigned char **ppBuf, int *pLength ) { NTSTATUS status; //CPR_BUFFER_TYPE *ToNetBuf = &devExt->ToNetBuf; // routine will use the buffer in devExt->ToNetBuf. // If it is contiguous, it will pass the position of the // RdPos pointer. Otherwise, align the data at the beginning // and return this. // if (ToNetBuf->WrPos == ToNetBuf->RdPos) { status = STATUS_NO_DATA_DETECTED; *ppBuf = NULL; } else { if (ToNetBuf->WrPos > ToNetBuf->RdPos) { *pLength = ToNetBuf->WrPos - ToNetBuf->RdPos; *ppBuf = &ToNetBuf->Buffer[ ToNetBuf->RdPos ]; status = STATUS_SUCCESS; } else { // Wraps around. Need to move memory to // the beginning of the buffer. This does // not happen too often. // CPR_BUFFER_TYPE tmpBuf; int endLen = sizeof(ToNetBuf->Buffer) - ToNetBuf->RdPos; int newWrPos = ToNetBuf->WrPos + endLen; //DbgPrint("Buffer Wrap Around: endLen %d WrPos %d, newWrPos %d, bufSize %d\n", // endLen, ToNetBuf->WrPos, newWrPos, sizeof(ToNetBuf->Buffer)); RtlMoveMemory(tmpBuf.Buffer, ToNetBuf->Buffer, ToNetBuf->WrPos); RtlMoveMemory(ToNetBuf->Buffer, &ToNetBuf->Buffer[ToNetBuf->RdPos], endLen); RtlMoveMemory(&ToNetBuf->Buffer[endLen], tmpBuf.Buffer, ToNetBuf->WrPos); ToNetBuf->RdPos = 0; ToNetBuf->WrPos = newWrPos; *pLength = newWrPos; *ppBuf = ToNetBuf->Buffer; status = STATUS_SUCCESS; } ToNetBuf->RdPos = ToNetBuf->WrPos; } return status; } void LogMsg( PCPR_DEVICE_EXTENSION devExt, char *msgArg) { if (LoggingEvent) { CprLogEvent( CPR_EVENT_TYPE_RFC2217, CPR_EVENT_SUB_TYPE_NONE, devExt, STATUS_SUCCESS, msgArg); } } LogModemState( PCPR_DEVICE_EXTENSION devExt, unsigned char mstate ) { char Msg[CPR_EVENT_MSG_SIZE]; if (LoggingEvent) { RtlStringCchPrintfA( Msg, sizeof(Msg), "DCTS %d, DDSR %d, TERI %d, DCD %d, CTS %d, DSR %d, RI %d, CD %d", (mstate & CPR_UART_MSR_DCTS) ? 1 : 0, (mstate & CPR_UART_MSR_DDSR) ? 1 : 0, (mstate & CPR_UART_MSR_TERI) ? 1 : 0, (mstate & CPR_UART_MSR_DDCD) ? 1 : 0, (mstate & CPR_UART_MSR_CTS) ? 1 : 0, (mstate & CPR_UART_MSR_DSR) ? 1 : 0, (mstate & CPR_UART_MSR_RI) ? 1 : 0, (mstate & CPR_UART_MSR_DCD) ? 1 : 0 ); LogMsg(devExt, Msg); } } LogLineState( PCPR_DEVICE_EXTENSION devExt, unsigned char lstate ) { char Msg[CPR_EVENT_MSG_SIZE]; if (LoggingEvent) { RtlStringCchPrintfA( Msg, sizeof(Msg), "TO %d, TSRE %d, THRE %d, BD %d, FE %d, PE %d, OE %d, DR %d", (lstate & 0x80) ? 1 : 0, (lstate & 0x40) ? 1 : 0, (lstate & 0x20) ? 1 : 0, (lstate & 0x10) ? 1 : 0, (lstate & 0x08) ? 1 : 0, (lstate & 0x04) ? 1 : 0, (lstate & 0x02) ? 1 : 0, (lstate & 0x01) ? 1 : 0 ); LogMsg(devExt, Msg); } }