// vuart.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "vuart.tmh" #endif //#define INADDR_BROADCAST ((ULONG)0xffffffff) /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartInitialize // initializes virtual uart extension // // Arguments: // IN Uart // uart device extension // // Return Value: // None // NTSTATUS CprUartInitialize( IN PCPR_UART Uart, IN PCPR_DEVICE_EXTENSION DeviceExtension ) { RtlZeroMemory(Uart, sizeof(CPR_UART)); // remember the parent device extension Uart->DeviceExtension = DeviceExtension; // allocate memory for receive buffer Uart->RxBuffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, CPR_POOL_TAG_UART); if (Uart->RxBuffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // allocate memory for transmit buffer Uart->TxBuffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, CPR_POOL_TAG_UART); if (Uart->TxBuffer == NULL) { ExFreePool(Uart->RxBuffer); Uart->RxBuffer = NULL; return STATUS_INSUFFICIENT_RESOURCES; } if ( !DeviceExtension->UseRFC2217 ) { // Initialize the DSR and CTS to active. // so an application not using RFC2217 can assume // a serial device is connected to the com port. DAG: 3/9/10 Uart->Msr |= CPR_UART_MSR_DSR | CPR_UART_MSR_CTS | CPR_UART_MSR_DCD; } Uart->RxReadPtr = Uart->RxWritePtr = Uart->RxBuffer; Uart->RxEndBuffer = Uart->RxBuffer + PAGE_SIZE; Uart->TxReadPtr = Uart->TxWritePtr = Uart->TxBuffer; Uart->TxSendBegPtr = Uart->TxSendEndPtr = Uart->TxBuffer; Uart->TxEndBuffer = Uart->TxBuffer + PAGE_SIZE; // initialize event dpc, used to signal uart events KeInitializeDpc(&Uart->EventDpc, CprUartEventDpcCallback, DeviceExtension); return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReInitialize // initializes virtual uart extension // // Arguments: // IN Uart // uart device extension // // Return Value: // None // NTSTATUS CprUartReinitialize( IN PCPR_UART Uart, IN PCPR_DEVICE_EXTENSION DeviceExtension ) { // remember the parent device extension Uart->DeviceExtension = DeviceExtension; if (Uart->RxBuffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } if (Uart->TxBuffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Uart->TxRFC2217Additional = 0; Uart->RxReadPtr = Uart->RxWritePtr = Uart->RxBuffer; Uart->RxEndBuffer = Uart->RxBuffer + PAGE_SIZE; Uart->TxReadPtr = Uart->TxWritePtr = Uart->TxBuffer; Uart->TxSendBegPtr = Uart->TxSendEndPtr = Uart->TxBuffer; Uart->TxEndBuffer = Uart->TxBuffer + PAGE_SIZE; // initialize event dpc, used to signal uart events KeInitializeDpc(&Uart->EventDpc, CprUartEventDpcCallback, DeviceExtension); return STATUS_SUCCESS; } //void CprDumpBufPtrs( // IN PCPR_DEVICE_EXTENSION DeviceExtension, // char *msg // ) //{ // PCPR_UART Uart = &DeviceExtension->Uart; // // DbgPrint("\n Uart Buffer Pointers: %s\n PendingWriteCount %d\n CurrentIrp %p\n", // msg, DeviceExtension->PendingWriteCount, DeviceExtension->WriteQueue.CurrentIrp); // // DbgPrint(" RxBuffer %p\n RxEndBuffer %p\n RxReadPtr %p\n RxWritePtr %p\n", // Uart->RxBuffer, Uart->RxEndBuffer, Uart->RxReadPtr, Uart->RxWritePtr); // // DbgPrint(" TxBuffer %p\n TxEndBuffer %p\n TxReadPtr %p\n TxWritePtr %p\n", // Uart->TxBuffer, Uart->TxEndBuffer, Uart->TxReadPtr, Uart->TxWritePtr); // // DbgPrint(" TxSendBegPtr %p\n TxSendEndPtr %p\n TxTdiWrLen %d\n TxSerWrLen %d\n\n", // Uart->TxSendBegPtr, Uart->TxSendEndPtr, Uart->TxTdiWriteLength, Uart->TxSerialWriteLength); //} /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartFree // frees virtual uart extension // // Arguments: // IN Uart // uart device extension // // Return Value: // None // VOID CprUartFree( IN PCPR_UART Uart ) { if (Uart->RxBuffer != NULL) { ExFreePool(Uart->RxBuffer); Uart->RxBuffer = NULL; Uart->RxEndBuffer = NULL; Uart->RxReadPtr = NULL; Uart->RxWritePtr = NULL; ExFreePool(Uart->TxBuffer); Uart->TxBuffer = NULL; Uart->TxEndBuffer = NULL; Uart->TxReadPtr = NULL; Uart->TxWritePtr = NULL; } return; } //VOID CprParseService(char *service, char* ipAddr, USHORT *port) //{ // NTSTATUS status; // USHORT tmp[5]; // int i, j, mult; // // // increment past the TYPE // service += 3; // // // extract IP Address // for (i = 3; (service[i] != ':') && (service[i] != '\0'); i++) // { // ipAddr[i-3] = service[i]; // } // // ipAddr[i-3] = '\0'; // // if (service[i] == ':') // { // // Extract and convert port // *port = 0; // // First collect values // i++; // for (j = 0; (j < 5) && (service[i] != '\0'); i++) // { // tmp[j] = service[i] - 0x30; // } // // // now take care of the proper places of 10 // mult = 1; // for (i = j; i > 0; i++) // { // *port += tmp[i] * mult; // mult *= 10; // } // } //} /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartIsLantronixDevice // Is this device a Lantronix device? // // Arguments: // IN Uart // uart device extension // // IN in_addr // remote IP address // // Return Value: // Status // // Comment: // BOOLEAN CprUartIsLantronixDevice( IN PCPR_UART Uart, ULONG in_addr, BOOLEAN doCall ) { PCPR_DEVICE_EXTENSION pDevExt; BOOLEAN result = TRUE; pDevExt = Uart->DeviceExtension; CprDebugPrint3( pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. addr %X, doCall %d, perfLock %d", in_addr, doCall, g_Data.PerformLockToLtx); CprDebugPrint4( pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" validated %d, count %d, interval %d, testAgain %d", pDevExt->Validated[pDevExt->CurService], pDevExt->LtxLockCount, pDevExt->LtxLockInterval, pDevExt->LtxLockTestAgain); if (g_Data.PerformLockToLtx) { // Need to revalidate every pDevExt->LtxLockInterval Intervals. // if ((pDevExt->Validated[pDevExt->CurService] == TRUE) && (pDevExt->LtxLockCount < pDevExt->LtxLockInterval) && (pDevExt->LtxLockCount != pDevExt->LtxLockTestAgain)) { pDevExt->LtxLockCount++; } else { if (doCall) { //DbgPrint("Calling CprUartUdpConfigPorts: Com %d Net %d Cnt %d", // pDevExt->ComStatus, pDevExt->NetworkStatus, pDevExt->LtxLockCount); if (pDevExt->LtxLockCount == pDevExt->LtxLockTestAgain) pDevExt->LtxLockCount++; else pDevExt->LtxLockCount = 1; NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_VERIFYING); if (CprUartUdpConfigPorts(Uart, in_addr) != STATUS_SUCCESS) { pDevExt->LtxLockCount = 1; result = FALSE; } } else { result = FALSE; } } } if (doCall) pDevExt->Validated[pDevExt->CurService] = result; CprDebugPrint3(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. result %d, validated %d, count %d", result, pDevExt->Validated[pDevExt->CurService], pDevExt->LtxLockCount); return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartUdpConfigPorts // Check to see if the device on the other end of the // network is a Lantronix device using UDP on the config ports. // Cobos = send port 0x77FE (30718) // Gordian = send port 0xA912 (43282) // receive port 0xA913 (43283) // // Arguments: // IN Uart // uart device extension // // IN in_addr // remote IP address // // Return Value: // Status // // Comment: // // Must be called at Passive IRQL // NTSTATUS CprUartUdpConfigPorts( IN PCPR_UART Uart, ULONG in_addr ) { int tries; NTSTATUS status = STATUS_CONNECTION_INVALID; NTSTATUS status1, status2; USHORT port; PCPR_DEVICE_EXTENSION pDevExt; PCPR_TDI_SOCKET socket; TA_IP_ADDRESS IpAddress; PCPR_TDI_SOCKET gordianRecvSocket; TA_IP_ADDRESS gordianRecvIpAddress; TDI_CONNECTION_INFORMATION cobosConnectInfo; TA_IP_ADDRESS cobosRemAddr; UCHAR cobosCmd[4]; PMDL cobosMdl; TDI_CONNECTION_INFORMATION gordianConnectInfo; TA_IP_ADDRESS gordianRemAddr; UCHAR gordianCmd[8]; PMDL gordianMdl; UCHAR *p; TDI_CONNECTION_INFORMATION gordianRecvConnectInfo; TA_IP_ADDRESS gordianRecvRemAddr; PVOID waitObjects[2]; KIRQL oldIrql; LARGE_INTEGER udpSendTimeout; LARGE_INTEGER timeout; ULONG base; ULONG round; // Send UDP requests on both Cobos and Gordian ports // If one returns, we have a Lantronix device. // Otherwise let the polling timeout. // Try several times, just in case the UDP packet // was dropped somewhere along the line. // pDevExt = Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++."); p = pDevExt->MacAddress; p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; p = pDevExt->DeviceId; p[0] = p[1] = p[2] = p[3] = 0; base = pDevExt->CnTmo / g_Data.NumLtxRequests; round = 0; // odd numbers need to add 500 milliseconds if (base % 2) round = 500; if (base == 0) base = 1; udpSendTimeout.QuadPart = -25000000; // 2.5 seconds timeout.QuadPart = ((base * 1000) + round) * 10000; timeout = RtlLargeIntegerNegate(timeout); // Open and use Send Socket // socket = CprTdiCreateSocket(UDP_DEVICE_NAME); if (socket != NULL) { // Remember our Uart for the completion routine. // socket->Uart = Uart; // Bind to local address on port 0xA912 // Cobos does not care if local port is // 0xA912, but Gordian does. // IpAddress.TAAddressCount = 1; IpAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); IpAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; IpAddress.Address[0].Address[0].sin_port = htons((short)0xA912); IpAddress.Address[0].Address[0].in_addr = 0; status = CprTdiOpenAddress(socket, (PTRANSPORT_ADDRESS)&IpAddress); if (NT_SUCCESS(status)) { // Bind to remote addresses: // // For Cobos: // Device IP Address // Port 0x77FE // cobosRemAddr.TAAddressCount = 1; cobosRemAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); cobosRemAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; cobosRemAddr.Address[0].Address[0].sin_port = htons((short)0x77FE); cobosRemAddr.Address[0].Address[0].in_addr = in_addr; RtlZeroMemory(&cobosConnectInfo, sizeof(TDI_CONNECTION_INFORMATION)); cobosConnectInfo.RemoteAddress = &cobosRemAddr; cobosConnectInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS); // For Gordian: // Device IP Address // Port 0xA912 // (NOTE: For Gordian, send on port 0xA912, receive on port 0xA913.) // gordianRemAddr.TAAddressCount = 1; gordianRemAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); gordianRemAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; gordianRemAddr.Address[0].Address[0].sin_port = htons((short)0xA912); gordianRemAddr.Address[0].Address[0].in_addr = in_addr; RtlZeroMemory(&gordianConnectInfo, sizeof(TDI_CONNECTION_INFORMATION)); gordianConnectInfo.RemoteAddress = &gordianRemAddr; gordianConnectInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS); // Set up socket Event Handlers // CprTdiSetEventHandler(socket, TDI_EVENT_RECEIVE_DATAGRAM, CprTdiEventReceiveConfigDatagram, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR, CprTdiEventError, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, socket); // Now setup the Gordian receive socket. // Note, again: Cobos will receive on 0x77FE // but will send the response back on whatever // the source port was in the packet // Setup up to receive on port 0xA913 and any IP address. // The "any" will be the local IP address. // gordianRecvSocket = CprTdiCreateSocket(UDP_DEVICE_NAME); if (gordianRecvSocket != NULL) { gordianRecvSocket->Uart = Uart; gordianRecvIpAddress.TAAddressCount = 1; gordianRecvIpAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); gordianRecvIpAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; gordianRecvIpAddress.Address[0].Address[0].sin_port = htons((short)0xA913); gordianRecvIpAddress.Address[0].Address[0].in_addr = 0; // Any Address // gordianRecvIpAddress.Address[0].Address[0].in_addr = INADDR_BROADCAST; // Broadcast Address //CprDebugPrint(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" before CprTdiOpenAddress"); status = CprTdiOpenAddress(gordianRecvSocket, (PTRANSPORT_ADDRESS)&gordianRecvIpAddress); //CprDebugPrint(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" after CprTdiOpenAddress"); if (NT_SUCCESS(status)) { // Set up gordianRecvSocket Event Handlers // CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_RECEIVE_DATAGRAM, CprTdiEventReceiveConfigDatagram, gordianRecvSocket); CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_ERROR, CprTdiEventError, gordianRecvSocket); CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, gordianRecvSocket); // Initialize commands // cobosCmd[0] = 0; cobosCmd[1] = 0x01; cobosCmd[2] = 0; cobosCmd[3] = 0xF6; // Configuration Request Command gordianCmd[0] = 1; gordianCmd[1] = 1; // SAUCEOP_QUERY Command gordianCmd[2] = 0; // padding gordianCmd[3] = 0; // padding gordianCmd[4] = 0x00; // MAC start gordianCmd[5] = 0xFF; // MAC end gordianCmd[6] = 0; gordianCmd[7] = 0; waitObjects[0] = &socket->LtxLockEvent; waitObjects[1] = &gordianRecvSocket->LtxLockEvent; //DbgPrint("Before for loop\n"); for (tries = 0; tries < g_Data.NumLtxRequests; tries++) { KeClearEvent(&socket->LtxLockEvent); KeClearEvent(&gordianRecvSocket->LtxLockEvent); if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartUdpConfigPorts, Cobos", cobosCmd, sizeof(cobosCmd)); CprDumpBuffer("CprUartUdpConfigPorts, Gordian", gordianCmd, sizeof(gordianCmd)); } // Send to Cobos // cobosMdl = IoAllocateMdl(cobosCmd, sizeof(cobosCmd), FALSE, FALSE, NULL); if (cobosMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(cobosMdl); status1 = CprTdiSendDatagram(socket, cobosMdl, sizeof(cobosCmd), &cobosConnectInfo, &udpSendTimeout); if (status1 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status1; break; } cobosCmd[1] = 0x00; cobosMdl = IoAllocateMdl(cobosCmd, sizeof(cobosCmd), FALSE, FALSE, NULL); if (cobosMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(cobosMdl); status1 = CprTdiSendDatagram(socket, cobosMdl, sizeof(cobosCmd), &cobosConnectInfo, &udpSendTimeout); if (status1 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status1; break; } // Send to Gordian // gordianMdl = IoAllocateMdl(gordianCmd, sizeof(gordianCmd), FALSE, FALSE, NULL); if (gordianMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(gordianMdl); status2 = CprTdiSendDatagram(socket, gordianMdl, sizeof(gordianCmd), &gordianConnectInfo, &udpSendTimeout); if (status2 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status2; break; } p = pDevExt->MacAddress; // Now wait for Cobos device or the Gordian // device to respond or the timeout fires. // KeWaitForMultipleObjects( 2, waitObjects, WaitAny, Executive, KernelMode, FALSE, &timeout, NULL); if ((p[0] != 0) || (p[1] != 0) || (p[2] != 0) || (p[3] != 0) || (p[4] != 0) || (p[5] != 0)) { status = STATUS_SUCCESS; break; } else { status = STATUS_IO_TIMEOUT; } } } CprTdiDeleteSocket(gordianRecvSocket); } } CprTdiDeleteSocket(socket); } CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. STATUS 0x%08X", status); return status; } typedef struct _CPR_UDP_PURGE_CONTEXT { PCPR_DEVICE_EXTENSION DeviceExtension; PIO_WORKITEM WorkItem; KEVENT purgeEvent; BOOLEAN purgeRx; BOOLEAN purgeTx; } CPR_UDP_PURGE_CONTEXT, *PCPR_UDP_PURGE_CONTEXT; /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartUdpPurgeBuffers // Purge Buffers via 0x50 purge command on the 0x77FE port. // // Arguments: // PCPR_DEVICE_EXTENSION pDevExt, // BOOLEAN purgeRx, // BOOLEAN purgeTx // // Return Value: // NTSTATUS // // Comment: // // Must be called with Serial Lock *NOT* Held // NTSTATUS CprUartUdpPurgeBuffers( PCPR_DEVICE_EXTENSION pDevExt, BOOLEAN purgeRx, BOOLEAN purgeTx ) { PCPR_UDP_PURGE_CONTEXT purgeContext; NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT deviceObject; LARGE_INTEGER udpSendTimeout; //KEVENT purgeEvent; purgeContext = (PCPR_UDP_PURGE_CONTEXT)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_UDP_PURGE_CONTEXT), CPR_POOL_TAG_PURGE_CONTEXT ); if (purgeContext != NULL) { if (pDevExt->socket && pDevExt->socket->ConnectionFileObject) { deviceObject = IoGetRelatedDeviceObject(pDevExt->socket->ConnectionFileObject); purgeContext->WorkItem = IoAllocateWorkItem(deviceObject); purgeContext->DeviceExtension = pDevExt; purgeContext->purgeRx = purgeRx; purgeContext->purgeTx = purgeTx; //purgeContext->pPurgeEvent = &purgeEvent; } else purgeContext->WorkItem = NULL; if (purgeContext->WorkItem != NULL) { KeInitializeEvent(&purgeContext->purgeEvent, NotificationEvent, FALSE); udpSendTimeout.QuadPart = 20000000; // 2.0 seconds udpSendTimeout = RtlLargeIntegerNegate(udpSendTimeout); //DbgPrint(__FUNCTION__" CprUartUdpPurgeBuffers-Before, IRQL %d \n", KeGetCurrentIrql()); IoQueueWorkItem( purgeContext->WorkItem, CprUartUdpPurgeBuffers_WorkerRoutine, DelayedWorkQueue, purgeContext); #ifdef IMTESTING if (KeGetCurrentIrql() != DISPATCH_LEVEL) { #endif KeWaitForSingleObject(&purgeContext->purgeEvent, Executive, KernelMode, FALSE, &udpSendTimeout); #ifdef IMTESTING } #endif } else { status = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(purgeContext); } } else { status = STATUS_INSUFFICIENT_RESOURCES; } return status; } BOOLEAN IsHostName(char *ipAddr) { BOOLEAN retval = FALSE; int i; for (i = 0; i < IP_MAC_HOST_LEN; i++) { char ch = ipAddr[i]; if (ch == '\0') break; if (ch == ':') { // Is a MAC address retval = FALSE; break; } if (((ch < '0') || (ch > '9')) && (ch != '.')) { retval = TRUE; } } return retval; } BOOLEAN IsMacAddress(char *ipAddr) { BOOLEAN invalidChar = FALSE; int i; int cnt = 0; for (i = 0; i < IP_MAC_HOST_LEN; i++) { char ch = ipAddr[i]; if (ch == '\0') break; if (ch == ':') { ++cnt; } else if ((ch < '0') || (ch > '9')) { if ((ch < 'A') || (ch > 'F')) { if ((ch < 'a') || (ch > 'f')) { invalidChar = TRUE; break; } } } } // may not be a completely valid Mac Address. // However, the user meant it to be a MAC address. // for example ":::::" will pass, 00:20::: will pass, etc. // but return TRUE anyways. if ((invalidChar == FALSE) && (cnt == 5)) return TRUE; return FALSE; } int _httoi(const char *value) { int result = 0; int ch; while (*value != '\0') { ch = *value; result <<= 4; if ((ch >= '0') && (ch <= '9')) result |= ch - '0'; else result |= (ch & 0xDF) - 'a' + 0xA; value++; } return result; } void ParseMacString( PCPR_DEVICE_EXTENSION pDevExt, char* macStr ) { int prev = 0; int ndx = 0; int i; for (i = 0; i < IP_MAC_HOST_LEN; i++) { int ch = macStr[i]; if (ch == '\0') break; if (ch == ':') { macStr[i] = '\0'; if (ndx >= MAC_LEN) break; pDevExt->MacAddress[ndx++] = (UCHAR)_httoi(&macStr[prev]); prev = i+1; } } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprResolveMacAddress // Take the // // Arguments: // IN Uart // uart device extension // // IN in_addr // remote IP address // // Return Value: // Status // // Comment: // // Must be called at Passive IRQL // NTSTATUS CprResolveMacAddress( PCPR_UART Uart, char *macStr // size is IP_MAC_HOST_LEN ) { // // ======================================================== // ======================================================== // // This needs to be re-written // to use Winsock Kernel (WSK) // IP Helper function GetIpInterfaceTable() // only available in Vista and Windows 7 on up. // // ======================================================== // ======================================================== // int tries; NTSTATUS status = STATUS_CONNECTION_INVALID; NTSTATUS status1, status2; USHORT port; PCPR_DEVICE_EXTENSION pDevExt; PCPR_TDI_SOCKET socket; TA_IP_ADDRESS IpAddress; PCPR_TDI_SOCKET gordianRecvSocket; TA_IP_ADDRESS gordianRecvIpAddress; TDI_CONNECTION_INFORMATION cobosConnectInfo; TA_IP_ADDRESS cobosRemAddr; UCHAR cobosCmd[4]; PMDL cobosMdl; TDI_CONNECTION_INFORMATION gordianConnectInfo; TA_IP_ADDRESS gordianRemAddr; UCHAR gordianCmd[8]; PMDL gordianMdl; TDI_CONNECTION_INFORMATION gordianRecvConnectInfo; TA_IP_ADDRESS gordianRecvRemAddr; PVOID waitObjects[2]; KIRQL oldIrql; LARGE_INTEGER udpSendTimeout; LARGE_INTEGER timeout; ULONG base; ULONG round; // Send UDP requests on both Cobos and Gordian ports // If one returns, we have a Lantronix device. // Otherwise let the polling timeout. // Try several times, just in case the UDP packet // was dropped somewhere along the line. // pDevExt = Uart->DeviceExtension; CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. MAC %s", macStr); ParseMacString(pDevExt, macStr); pDevExt->ResolvedIpAddress = 0; base = pDevExt->CnTmo / g_Data.NumLtxRequests; round = 0; // odd numbers need to add 500 milliseconds if (base % 2) round = 500; if (base == 0) base = 1; udpSendTimeout.QuadPart = -25000000; // 2.5 seconds timeout.QuadPart = ((base * 1000) + round) * 10000; timeout = RtlLargeIntegerNegate(timeout); // Open and use Send Socket // socket = CprTdiCreateSocket(UDP_DEVICE_NAME); if (socket != NULL) { // Remember our Uart for the completion routine. // socket->Uart = Uart; // Bind to local address on port 0xA912 // Cobos does not care if local port is // 0xA912, but Gordian does. // IpAddress.TAAddressCount = 1; IpAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); IpAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; IpAddress.Address[0].Address[0].sin_port = htons((short)0xA912); IpAddress.Address[0].Address[0].in_addr = 0; status = CprTdiOpenAddress(socket, (PTRANSPORT_ADDRESS)&IpAddress); if (NT_SUCCESS(status)) { // Bind to remote addresses: // // For Cobos: // Device IP Address // Port 0x77FE // cobosRemAddr.TAAddressCount = 1; cobosRemAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); cobosRemAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; cobosRemAddr.Address[0].Address[0].sin_port = htons((short)0x77FE); cobosRemAddr.Address[0].Address[0].in_addr = INADDR_BROADCAST; RtlZeroMemory(&cobosConnectInfo, sizeof(TDI_CONNECTION_INFORMATION)); cobosConnectInfo.RemoteAddress = &cobosRemAddr; cobosConnectInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS); // For Gordian: // Device IP Address // Port 0xA912 // (NOTE: For Gordian, send on port 0xA912, receive on port 0xA913.) // gordianRemAddr.TAAddressCount = 1; gordianRemAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); gordianRemAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; gordianRemAddr.Address[0].Address[0].sin_port = htons((short)0xA912); gordianRemAddr.Address[0].Address[0].in_addr = INADDR_BROADCAST; RtlZeroMemory(&gordianConnectInfo, sizeof(TDI_CONNECTION_INFORMATION)); gordianConnectInfo.RemoteAddress = &gordianRemAddr; gordianConnectInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS); // Set up socket Event Handlers // CprTdiSetEventHandler(socket, TDI_EVENT_RECEIVE_DATAGRAM, CprTdiEventReceiveMacResolutionDatagram, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR, CprTdiEventError, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, socket); // Now setup the Gordian receive socket. // Note, again: Cobos will receive on 0x77FE // but will send the response back on whatever // the source port was in the packet // Setup up to receive on port 0xA913 and any IP address. // The "any" will be the local IP address. // gordianRecvSocket = CprTdiCreateSocket(UDP_DEVICE_NAME); if (gordianRecvSocket != NULL) { gordianRecvSocket->Uart = Uart; gordianRecvIpAddress.TAAddressCount = 1; gordianRecvIpAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); gordianRecvIpAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; gordianRecvIpAddress.Address[0].Address[0].sin_port = htons((short)0xA913); gordianRecvIpAddress.Address[0].Address[0].in_addr = 0; // Any Address status = CprTdiOpenAddress(gordianRecvSocket, (PTRANSPORT_ADDRESS)&gordianRecvIpAddress); if (NT_SUCCESS(status)) { // Set up gordianRecvSocket Event Handlers // CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_RECEIVE_DATAGRAM, CprTdiEventReceiveMacResolutionDatagram, gordianRecvSocket); CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_ERROR, CprTdiEventError, gordianRecvSocket); CprTdiSetEventHandler(gordianRecvSocket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, gordianRecvSocket); // Initialize commands // cobosCmd[0] = 0; cobosCmd[1] = 0x01; cobosCmd[2] = 0; cobosCmd[3] = 0xF6; // Configuration Request Command gordianCmd[0] = 1; gordianCmd[1] = 1; // SAUCEOP_QUERY Command gordianCmd[2] = 0; // padding gordianCmd[3] = 0; // padding gordianCmd[4] = 0x00; // MAC start gordianCmd[5] = 0xFF; // MAC end gordianCmd[6] = 0; gordianCmd[7] = 0; waitObjects[0] = &socket->LtxLockEvent; waitObjects[1] = &gordianRecvSocket->LtxLockEvent; //DbgPrint("Before for loop\n"); for (tries = 0; tries < g_Data.NumLtxRequests; tries++) { KeClearEvent(&socket->LtxLockEvent); KeClearEvent(&gordianRecvSocket->LtxLockEvent); if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartUdpConfigPorts, Cobos", cobosCmd, sizeof(cobosCmd)); } // Send to Cobos // cobosMdl = IoAllocateMdl(cobosCmd, sizeof(cobosCmd), FALSE, FALSE, NULL); if (cobosMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(cobosMdl); status1 = CprTdiSendDatagram(socket, cobosMdl, sizeof(cobosCmd), &cobosConnectInfo, &udpSendTimeout); if (status1 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status1; break; } cobosCmd[1] = 0x00; cobosMdl = IoAllocateMdl(cobosCmd, sizeof(cobosCmd), FALSE, FALSE, NULL); if (cobosMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(cobosMdl); status1 = CprTdiSendDatagram(socket, cobosMdl, sizeof(cobosCmd), &cobosConnectInfo, &udpSendTimeout); if (status1 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status1; break; } // Send to Gordian // gordianMdl = IoAllocateMdl(gordianCmd, sizeof(gordianCmd), FALSE, FALSE, NULL); if (gordianMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(gordianMdl); status2 = CprTdiSendDatagram(socket, gordianMdl, sizeof(gordianCmd), &gordianConnectInfo, &udpSendTimeout); if (status2 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status2; break; } // Now wait for Cobos device or the Gordian // device to respond or the timeout fires. // KeWaitForMultipleObjects( 2, waitObjects, WaitAny, Executive, KernelMode, FALSE, &timeout, NULL); if (pDevExt->ResolvedIpAddress != 0) { status = STATUS_SUCCESS; break; } else { status = STATUS_IO_TIMEOUT; } } } CprTdiDeleteSocket(gordianRecvSocket); } } CprTdiDeleteSocket(socket); } CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. STATUS 0x%08X IpAddress %X", status, pDevExt->ResolvedIpAddress); return status; } CopyWCharToChar(char *dst, WCHAR *src) { int i; for (i = 0; i < IP_MAC_HOST_LEN; i++) { dst[i] = (char)src[i]; } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartUdpPurgeBuffers_WorkerRoutine // Purge Buffers via 0x50 purge command on the 0x77FE port. // // Arguments: // IN PDEVICE_OBJECT DeviceObject, // IN PVOID Context // // Return Value: // // // Comment: // // Must be called with Serial Lock *NOT* Held // VOID CprUartUdpPurgeBuffers_WorkerRoutine( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context ) { int tries; NTSTATUS status = STATUS_CONNECTION_INVALID; NTSTATUS status1; USHORT port; PCPR_DEVICE_EXTENSION pDevExt; BOOLEAN purgeRx; BOOLEAN purgeTx; PCPR_UDP_PURGE_CONTEXT purgeContext; PCPR_TDI_SOCKET socket; TA_IP_ADDRESS IpAddress; TDI_CONNECTION_INFORMATION cobosConnectInfo; TA_IP_ADDRESS cobosRemAddr; UCHAR cobosCmd[9]; PMDL cobosMdl; LARGE_INTEGER udpSendTimeout; purgeContext = (PCPR_UDP_PURGE_CONTEXT)Context; ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); pDevExt = purgeContext->DeviceExtension; purgeRx = purgeContext->purgeRx; purgeTx = purgeContext->purgeTx; udpSendTimeout.QuadPart = 15000000; // 1.5 seconds udpSendTimeout = RtlLargeIntegerNegate(udpSendTimeout); // Open and use Send Socket // socket = CprTdiCreateSocket(UDP_DEVICE_NAME); if (socket != NULL) { // // Remember our Uart for the completion routine. // // socket->Uart = &pDevExt->Uart; // Bind to local address on port 0xA912 // Cobos does not care if local port is // 0xA912, but Gordian does. // IpAddress.TAAddressCount = 1; IpAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); IpAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; IpAddress.Address[0].Address[0].sin_port = 0; IpAddress.Address[0].Address[0].in_addr = 0; status = CprTdiOpenAddress(socket, (PTRANSPORT_ADDRESS)&IpAddress); if (NT_SUCCESS(status)) { char addrStr[IP_MAC_HOST_LEN]; BOOLEAN okToContinue = TRUE; CopyWCharToChar(addrStr, pDevExt->Services[ pDevExt->CurService ].Address); if (IS_WIN7_OR_GREATER) { // Windows 7 on up. if (IsHostName(addrStr)) { if (ResolveHostName(pDevExt, addrStr) != STATUS_SUCCESS) { addrStr[0] = '\0'; okToContinue = FALSE; } } else if (IsMacAddress(addrStr)) { // ULONG r = pDevExt->ResolvedIpAddress; if (CprResolveMacAddress(&pDevExt->Uart, addrStr) == STATUS_SUCCESS) { // USE: //BOOLEAN inet_ntoa( // IN ULONG Address, // OUT PCHAR Buffer, // IN ULONG BufferLength // ) inet_ntoa(pDevExt->ResolvedIpAddress, addrStr, IP_MAC_HOST_LEN); //RtlStringCchPrintfA(addrStr, IP_MAC_HOST_LEN, "%d.%d.%d.%d", // (r >> 24) & 0xFF, (r >> 16) & 0xFF, (r >> 8) & 0xFF, r & 0xFF); } else { addrStr[0] = '\0'; okToContinue = FALSE; } } } CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" addr %s okToContinue %d", addrStr, okToContinue); if (okToContinue) { // Bind to remote addresses: // // For Cobos: // Device IP Address // Port 0x77FE // cobosRemAddr.TAAddressCount = 1; cobosRemAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); cobosRemAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; cobosRemAddr.Address[0].Address[0].sin_port = htons((short)0x77FE); cobosRemAddr.Address[0].Address[0].in_addr = inet_addr(addrStr); RtlZeroMemory(&cobosConnectInfo, sizeof(TDI_CONNECTION_INFORMATION)); cobosConnectInfo.RemoteAddress = &cobosRemAddr; cobosConnectInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS); // Set up socket Event Handlers // CprTdiSetEventHandler(socket, TDI_EVENT_RECEIVE_DATAGRAM, CprTdiEventReceiveConfigDatagram, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR, CprTdiEventError, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, socket); // Initialize command // cobosCmd[0] = 0x0; cobosCmd[1] = 0x01; // Don't reboot cobosCmd[2] = 0x0; cobosCmd[3] = 0x50; // Request Command cobosCmd[4] = 0x01; // Purge Command cobosCmd[5] = 0x03; // Number of bytes in payload port = (USHORT)pDevExt->Services[ pDevExt->CurService ].Port; cobosCmd[6] = (port >> 8) & 0xFF; cobosCmd[7] = port & 0xFF; //#define RFC2217_TCP_DUMP #ifdef RFC2217_TCP_DUMP cobosCmd[8] = 0x08; #else cobosCmd[8] = 0x04; if (purgeRx) cobosCmd[8] |= 0x02; if (purgeTx) cobosCmd[8] |= 0x01; #endif for (tries = 0; tries < 1; tries++) { //KeClearEvent(&socket->LtxLockEvent); if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer(__FUNCTION__" Cobos", cobosCmd, sizeof(cobosCmd)); } // Send to Cobos // cobosMdl = IoAllocateMdl(cobosCmd, sizeof(cobosCmd), FALSE, FALSE, NULL); if (cobosMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(cobosMdl); pDevExt->PurgeResponse = 0; status1 = CprTdiSendDatagram(socket, cobosMdl, sizeof(cobosCmd), &cobosConnectInfo, &udpSendTimeout); if (status1 != STATUS_SUCCESS) { // ARP must be failing... // Device is probably not powered up. status = status1; break; } // // Wait, below, has been place in routine that calls this worker thread. // // Now wait for Cobos device // device to respond or the timeout fires. // if (KeWaitForSingleObject(&socket->LtxLockEvent, Executive, KernelMode, FALSE, &udpSendTimeout) == STATUS_SUCCESS) { //DbgPrint(__FUNCTION__" Purge Received: %X\n", pDevExt->PurgeResponse); if (pDevExt->PurgeResponse == 0x81) status = STATUS_SUCCESS; break; } } } } CprTdiDeleteSocket(socket); } KeSetEvent(&purgeContext->purgeEvent, 0, FALSE); IoFreeWorkItem(purgeContext->WorkItem); ExFreePool(purgeContext); // return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartConnect // Open a new connection // // Arguments: // IN Uart // uart device extension // // Return Value: // Status // // Comment: // This method USED TO BE called with SerialLock held // HOWEVER, MANY FUNCTIONS CALLED IN THIS ROUTINE NEED // TO BE CALLED AT PASSIVE LEVEL. FOR EXAMPLE, // ZwCreateFile() and IoGetDeviceObjectPointer(). // NOW DO INTERMITTANT LOCKING OF SerialLock. // NTSTATUS CprUartConnect( IN PCPR_UART Uart, IN USHORT localPort ) { NTSTATUS status = STATUS_CONNECTION_INVALID; USHORT port; char ipAddr[20]; PCPR_DEVICE_EXTENSION pDevExt; ULONG service = 0; //ULONG attemptService = 0; KIRQL oldIrql = PASSIVE_LEVEL; SOCKET socket = NULL; SOCKET listenSocket = NULL; ULONG numServices; pDevExt = Uart->DeviceExtension; CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. pDevExt %p", pDevExt); if (pDevExt->NumServices > 0) { socket = pDevExt->socket; pDevExt->ListenSocket = NULL; if (socket == NULL) { socket = CprTdiCreateSocket(TCP_DEVICE_NAME); } if (socket != NULL) { TA_IP_ADDRESS ipAddress; // Associate a back pointer to this Uart socket->Uart = Uart; ipAddress.TAAddressCount = 1; ipAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); ipAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; if (pDevExt->ListenMode == LISTEN_MODE_NONE) ipAddress.Address[0].Address[0].sin_port = localPort; else // Listen Mode ipAddress.Address[0].Address[0].sin_port = htons((USHORT)(pDevExt->Services[0].Port)); ipAddress.Address[0].Address[0].in_addr = 0; status = CprTdiOpenAddress(socket, (PTRANSPORT_ADDRESS)&ipAddress); if (NT_SUCCESS(status)) { TDI_CONNECTION_INFORMATION connectionInformation; status = CprTdiOpenConnection(socket); if (NT_SUCCESS(status)) { status = CprTdiAssociateAddress(socket); if (NT_SUCCESS(status)) { if (pDevExt->ListenMode == LISTEN_MODE_NONE) { TA_IP_ADDRESS remoteAddress; remoteAddress.TAAddressCount = 1; remoteAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); remoteAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; CprTdiSetEventHandler(socket, TDI_EVENT_ERROR, CprTdiEventError, socket); CprTdiSetEventHandler(socket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, socket); CprTdiSetEventHandler(socket, TDI_EVENT_RECEIVE, CprTdiEventReceive, socket); CprTdiSetEventHandler(socket, TDI_EVENT_DISCONNECT, CprTdiEventDisconnect, socket); // Cooper Power: Disable Roll over if (g_Data.NoServiceRollover) numServices = 1; else numServices = pDevExt->NumServices; for (service = 0; service < numServices; service++) { char addrStr[IP_MAC_HOST_LEN]; BOOLEAN okToContinue = TRUE; CopyWCharToChar(addrStr, pDevExt->Services[ service ].Address); if (IS_WIN7_OR_GREATER) { DbgPrint("Is Windows 7 or greater\n"); // Vista, Windows 7 on up. if (IsHostName(addrStr)) { if (ResolveHostName(pDevExt, addrStr) != STATUS_SUCCESS) okToContinue = FALSE; } else if (IsMacAddress(addrStr)) { ULONG r = pDevExt->ResolvedIpAddress; if (CprResolveMacAddress(&pDevExt->Uart, addrStr) == STATUS_SUCCESS) RtlStringCchPrintfA(addrStr, IP_MAC_HOST_LEN, "%d.%d.%d.%d", (r >> 24) & 0xFF, (r >> 16) & 0xFF, (r >> 8) & 0xFF, r & 0xFF); else okToContinue = FALSE; } } else { DbgPrint("Is below Windows 7\n"); } CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" addr %s okToContinue %d", addrStr, okToContinue); if (okToContinue) { pDevExt->CurService = service; remoteAddress.Address[0].Address[0].in_addr = inet_addr(addrStr); if (CprUartIsLantronixDevice(Uart, remoteAddress.Address[0].Address[0].in_addr, TRUE)) { if (pDevExt->NetworkStatus != CPR_NETWORK_STATUS_RECONNECTING) NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_CONNECTING); remoteAddress.Address[0].Address[0].sin_port = htons((USHORT)(pDevExt->Services[ pDevExt->CurService ].Port)); RtlZeroMemory(&connectionInformation, sizeof(TDI_CONNECTION_INFORMATION)); connectionInformation.RemoteAddress = &remoteAddress; connectionInformation.RemoteAddressLength = sizeof(TA_IP_ADDRESS); CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_INFO, "Attempting to connect to '%s:%d'", addrStr, pDevExt->Services[ pDevExt->CurService ].Port); status = CprTdiConnect(socket, &connectionInformation, NULL); if (status == STATUS_SUCCESS) { char tmp[200]; PMDL aiMdl; NTSTATUS st; aiMdl = IoAllocateMdl(tmp, 200, FALSE, FALSE, NULL); if (aiMdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } MmBuildMdlForNonPagedPool(aiMdl); st = CprTdiQueryInformation(socket, TDI_QUERY_ADDRESS_INFO, aiMdl); if (st == STATUS_SUCCESS) { TDI_ADDRESS_INFO *pTdi_ai = (TDI_ADDRESS_INFO*)tmp; TA_ADDRESS *pTaa = (TA_ADDRESS*)pTdi_ai->Address.Address; TDI_ADDRESS_IP *pTdi_aip = (TDI_ADDRESS_IP*)pTaa->Address; socket->LocalPort = ntohs(pTdi_aip->sin_port); pDevExt->ReconnectPort = socket->LocalPort; if (pDevExt->KeepAliveOnOff == TRUE) { CprTdiSetKeepAlive(socket, TRUE); } CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_INFO, "############## Local Port %d", socket->LocalPort); } NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_CONNECTED); break; } } else { status = STATUS_IO_TIMEOUT; } } else { status = STATUS_CONNECTION_INVALID; } NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } } else { // Listen Mode listenSocket = socket; socket = NULL; // The connection socket will go here // once a connection has been made. CprAcquireSerialSpinLock(pDevExt, &oldIrql); CprTdiAllocateConnectSocketPool(listenSocket, 1); // Only allow 1 connection at a time. CprReleaseSerialSpinLock(pDevExt, oldIrql); CprTdiSetEventHandler(listenSocket, TDI_EVENT_ERROR, CprTdiEventError, listenSocket); CprTdiSetEventHandler(listenSocket, TDI_EVENT_ERROR_EX, CprTdiEventErrorEx, listenSocket); CprTdiSetEventHandler(listenSocket, TDI_EVENT_CONNECT, CprTdiEventConnect, listenSocket); CprTdiSetEventHandler(listenSocket, TDI_EVENT_DISCONNECT, CprTdiEventDisconnect, listenSocket); CprTdiSetEventHandler(listenSocket, TDI_EVENT_RECEIVE, CprTdiEventReceive, listenSocket); status = STATUS_SUCCESS; // Actually it is already STATUS_SUCCESS pDevExt->CurService = 0; //DbgPrint("Listening on port %d\n", ntohs(ipAddress.Address[0].Address[0].sin_port)); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_LISTENING); } } } //if (status != STATUS_SUCCESS) // pDevExt->CurService = 0; } } if (!NT_SUCCESS(status)) { if (socket != NULL) { CprDebugPrint3(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" Disconnecting from '%ws:%d' Status 0x%08X", pDevExt->Services[pDevExt->CurService].Address, pDevExt->Services[pDevExt->CurService].Port, status); CprTdiDisconnect(socket, FALSE, NULL, NULL); CprTdiDeleteSocket(socket); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } if (listenSocket != NULL) { CprDebugPrint3(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" Disconnecting from '%ws:%d' Status 0x%08X", pDevExt->Services[pDevExt->CurService].Address, pDevExt->Services[pDevExt->CurService].Port, status); CprTdiDisconnect(listenSocket, FALSE, NULL, NULL); CprTdiDeleteSocket(listenSocket); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } //pDevExt->socket = NULL; //pDevExt->ListenSocket = NULL; socket = NULL; listenSocket = NULL; pDevExt->CurService = 0; } else { //NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_CONNECTED); pDevExt->TxStopReason = 0; } } pDevExt->socket = socket; pDevExt->ListenSocket = listenSocket; CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. STATUS 0x%08X", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartClose // Close Uart Connection // // Arguments: // IN Uart // uart device extension // // Return Value: // None // // Comment: // This method used to be called with SerialLock held, NOW IT IS NOT!!! // NTSTATUS CprUartClose( IN PCPR_UART Uart ) { NTSTATUS status = STATUS_SUCCESS; PCPR_DEVICE_EXTENSION pDevExt = Uart->DeviceExtension; KIRQL oldIrql; SOCKET socket; SOCKET listenSocket; CprDebugPrint1(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. pDevExt %p", pDevExt); if ((pDevExt->socket != NULL) || pDevExt->ListenSocket != NULL) { CprAcquireSerialSpinLock(pDevExt, &oldIrql); socket = pDevExt->socket; listenSocket = pDevExt->ListenSocket; pDevExt->socket = NULL; pDevExt->ListenSocket = NULL; NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); CprReleaseSerialSpinLock(pDevExt, oldIrql); CprDebugPrint4(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" Disconnecting from '%ws:%d' Socket %p Listen %p", pDevExt->Services[pDevExt->CurService].Address, pDevExt->Services[pDevExt->CurService].Port, socket, listenSocket); if (listenSocket != NULL) { if (socket != NULL) { CprTdiFreeConnectSocket(socket); } CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_INFO, __FUNCTION__" Disconnecting from ListenSocket %p AddressHandle %p", listenSocket, listenSocket->AddressHandle); status = CprTdiDisconnect(listenSocket, FALSE, NULL, NULL); // status = CprTdiDisconnect(listenSocket, TRUE, NULL, NULL); CprTdiDeleteSocket(listenSocket); } else if (socket != NULL) { status = CprTdiDisconnect(socket, FALSE, NULL, NULL); // status = CprTdiDisconnect(socket, TRUE, NULL, NULL); CprTdiDeleteSocket(socket); } } CprDebugPrint(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--"); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartCheckEvents // checks for pending uart events // // Arguments: // IN Uart // uart device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprUartCheckEvents( IN PCPR_UART Uart ) { BOOLEAN bEvent; bEvent = FALSE; if (Uart->RxDataEvent && (Uart->Ier & CPR_UART_IER_RDA)) { // there is a pending receive event, and event mask allows us // to signal receive events bEvent = TRUE; } else if (Uart->TxEmptyEvent && (Uart->Ier & CPR_UART_IER_THR)) { // there is a pending transmit event, and event mask allows us // to signal transmit events bEvent = TRUE; } else if (Uart->LineStatusEvent && (Uart->Ier & CPR_UART_IER_RLS)) { // there is a pending line status event, and event mask allows us // to signal line status events bEvent = TRUE; } else if (Uart->ModemStatusEvent && (Uart->Ier & CPR_UART_IER_MS)) { // there is a pending modem status event, and event mask allows us // to signal modem status events bEvent = TRUE; } // There is a pending event, so fire a dpc to handle it if (bEvent) { KeInsertQueueDpc(&Uart->EventDpc, NULL, NULL); } return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWrite // writes a block of data // // Arguments: // IN Uart // uart device extension // // IN Buffer // characters to write // // IN Length // Number of characters to write // // Return Value: // None // // Comment: // This method is called with SerialLock held // This method is called on a DPC // NTSTATUS CprUartWrite( IN PCPR_UART Uart, IN UCHAR *Buffer, IN int Length ) { NTSTATUS status = !STATUS_SUCCESS; PCPR_DEVICE_EXTENSION pDevExt; PMDL mdl = NULL; pDevExt = Uart->DeviceExtension; // // This function is called with the SerialLock held. // Now that this routine is returning and the completion is done elsewhere // 1. What are the consequences of unlocking the SerialLock? // 2. Does the SerialLock need to be grabbed again in the // completion routine before processing? // CprDebugPrint3(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"++: Uart %p Buffer %p Length %d", Uart, Buffer, Length); if (pDevExt && Buffer) { pDevExt->SerialStats.TransmittedCount += Length; pDevExt->WmiPerfData.TransmittedCount += Length; if (pDevExt->UseRFC2217) { int i, ndx; PUCHAR rfc2217Buf = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, Length * 2, // worst case. CPR_POOL_TAG_RFC2217_BUF ); ndx = 0; for (i = 0; i < Length; i++) { rfc2217Buf[ndx++] = Buffer[i]; if (Buffer[i] == 0xFF) rfc2217Buf[ndx++] = 0xFF; } //CprDumpBuffer("CprUartWrite (RFC2217)", rfc2217Buf, ndx); if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartWrite (RFC2217)", rfc2217Buf, ndx); } #ifdef SCPR // Is AES turned on? if (pDevExt->AES) { CprEncrypt(pDevExt, rfc2217Buf, rfc2217Buf, ndx); } #endif mdl = IoAllocateMdl((PVOID)rfc2217Buf, ndx, FALSE, FALSE, NULL); // RFC2217 if ((pDevExt->BufferWrites) && (pDevExt->WriteQueue.CurrentIrp == NULL)) { Uart->TxRFC2217Additional = ndx - Length; //pDevExt->BfWriteCount += ndx - Length; } else { // Do we have a new length??? pDevExt->WriteLength += ndx - Length; } Length = ndx; } else { if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartWrite", Buffer, Length); } #ifdef SCPR // Is AES turned on? if (pDevExt->AES) { CprEncrypt(pDevExt, Buffer, Buffer, Length); } #endif mdl = IoAllocateMdl((PVOID)Buffer, Length, FALSE, FALSE, NULL); } if(!mdl) { status = STATUS_INSUFFICIENT_RESOURCES; } else { MmBuildMdlForNonPagedPool(mdl); status = CprTdiSend(pDevExt->socket, 0, mdl, Length); // status = CprTdiSend(pDevExt->socket, TDI_SEND_NON_BLOCKING | TDI_SEND_NO_RESPONSE_EXPECTED, mdl, Length); #ifdef USE_NO_WAIT_COMPLETE // DEBUG ////////////////// CprStartNext(&pDevExt->WriteQueue); // DEBUG ////////////////// #endif } } else status = STATUS_INTERNAL_ERROR; CprDebugPrint2(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"--: Uart %p Status %X", Uart, status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWriteImmediate // writes one character // // Arguments: // IN Uart // uart device extension // // IN Buffer // characters to write // // IN Length // Number of characters to write // // Return Value: // None // // Comment: // This method is called with SerialLock held // This method is called on a DPC // NTSTATUS CprUartWriteImmediate( IN PCPR_UART Uart, IN UCHAR *Buffer ) { NTSTATUS status = !STATUS_SUCCESS; PCPR_DEVICE_EXTENSION pDevExt; PMDL mdl = NULL; int Length = 1; pDevExt = Uart->DeviceExtension; // // This function is called with the SerialLock held. // Now that this routine is returning and the completion is done elsewhere // 1. What are the consequences of unlocking the SerialLock? // 2. Does the SerialLock need to be grabbed again in the // completion routine before processing? // CprDebugPrint2(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"++: Uart %p Buffer %p", Uart, Buffer); if (pDevExt != NULL) { pDevExt->SerialStats.TransmittedCount += Length; pDevExt->WmiPerfData.TransmittedCount += Length; if (pDevExt->UseRFC2217) { int i, ndx; PUCHAR rfc2217Buf = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, 2, // worst case. CPR_POOL_TAG_RFC2217_BUF ); ndx = 0; rfc2217Buf[ndx++] = Buffer[0]; if (Buffer[0] == 0xFF) rfc2217Buf[ndx++] = 0xFF; if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartWriteImmediate (RFC2217)", rfc2217Buf, ndx); } #ifdef SCPR // Is AES turned on? if (pDevExt->AES) { CprEncrypt(pDevExt, rfc2217Buf, rfc2217Buf, ndx); } #endif mdl = IoAllocateMdl((PVOID)rfc2217Buf, ndx, FALSE, FALSE, NULL); Length = ndx; } else { if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartWriteImmediate", Buffer, Length); } #ifdef SCPR // Is AES turned on? if (pDevExt->AES) { CprEncrypt(pDevExt, Buffer, Buffer, Length); } #endif mdl = IoAllocateMdl((PVOID)Buffer, Length, FALSE, FALSE, NULL); } if(!mdl) { status = STATUS_INSUFFICIENT_RESOURCES; } else { MmBuildMdlForNonPagedPool(mdl); status = CprTdiSendImmediate(pDevExt->socket, 0, mdl, Length); //if (status == STATUS_INVALID_DEVICE_STATE) //{ // CprTdiReconnect(pDevExt); //} } } CprDebugPrint2(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"--: Uart %p Status %X", Uart, status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWriteDirect // writes a block of data and waits // // Arguments: // IN Uart // uart device extension // // IN Buffer // characters to write // // IN Length // Number of characters to write // // Return Value: // None // // Comment: // This method is called with SerialLock held // This method is called on a DPC // NTSTATUS CprUartWriteDirect( IN PCPR_UART Uart, IN UCHAR *Buffer, IN int Length, BOOLEAN Wait, BOOLEAN okToEncrypt ) { NTSTATUS status = !STATUS_SUCCESS; PCPR_DEVICE_EXTENSION pDevExt; PMDL mdl = NULL; pDevExt = Uart->DeviceExtension; // // This function is called with the SerialLock held. // Now that this routine is returning and the completion is done elsewhere // 1. What are the consequences of unlocking the SerialLock? // 2. Does the SerialLock need to be grabbed again in the // completion routine before processing? // #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"++: Uart %p Buffer %p Length %d\n", Uart, Buffer, Length); #endif CprDebugPrint3(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"++: Uart %p Buffer %p Length %d", Uart, Buffer, Length); if (pDevExt != NULL) { pDevExt->SerialStats.TransmittedCount += Length; pDevExt->WmiPerfData.TransmittedCount += Length; if ((g_DebugArea & (DBG_WRITE | DBG_IO)) && (DBG_INFO <= g_DebugLevel)) { CprDumpBuffer("CprUartWriteDirect", Buffer, Length); } #ifdef SCPR // Is AES turned on? if (pDevExt->AES & okToEncrypt & pDevExt->AESInitVectorFlag) { CprEncrypt(pDevExt, Buffer, Buffer, Length); } #endif mdl = IoAllocateMdl((PVOID)Buffer, Length, FALSE, FALSE, NULL); if(!mdl) { status = STATUS_INSUFFICIENT_RESOURCES; } else { MmBuildMdlForNonPagedPool(mdl); status = CprTdiSendDirect(pDevExt->socket, 0 /*TDI_SEND_EXPEDITED*/, mdl, Length, Wait); } } #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"--: Uart %p Status %X\n", Uart, status); #endif CprDebugPrint2(pDevExt, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"--: Uart %p Status %X", Uart, status); return status; } void ProcessOverflow( IN PCPR_UART Uart ) { PIRP remainIrp; PCPR_TDI_SOCKET socket = Uart->DeviceExtension->socket; PUCHAR remainBuf; PDEVICE_OBJECT deviceObject; PMDL mdl; NTSTATUS status; ULONG bytesToGet = 0; PCPR_PROCESS_OVERFLOW_CONTEXT poCtx; // Prototype NTSTATUS CprTdiRemainComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); CprDebugPrint5(Uart->DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++. Uart %p OverflowSize %d RxCount %d Available %d PAGE_SIZE %d", Uart, Uart->OverflowSize, RxCount(Uart), RxAvailableCount(Uart), PAGE_SIZE); CprDebugPrint2(Uart->DeviceExtension, DBG_IO, DBG_INFO, __FUNCTION__" RxReadPtr %p RxWritePtr %p", Uart->RxReadPtr, Uart->RxWritePtr); if (Uart->OverflowSize > 0) { bytesToGet = Uart->OverflowSize; if (bytesToGet > RxAvailableCount(Uart)) bytesToGet = RxAvailableCount(Uart); if (bytesToGet != 0) { remainBuf = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, bytesToGet, CPR_POOL_TAG_REMAIN_BUF ); CprDebugPrint3(Uart->DeviceExtension, DBG_IO, DBG_INFO, __FUNCTION__" REQUESTING. OverflowSize %d bytesToGet %d Buf %p", Uart->OverflowSize, bytesToGet, remainBuf); if (remainBuf == NULL) return; remainIrp = CprTdiAllocIrp(socket); if (remainIrp == NULL) { ExFreePool(remainBuf); return; } remainIrp->UserEvent = &socket->Event; remainIrp->UserIosb = &socket->IoStatus; CprTdiAddRef(socket); deviceObject = IoGetRelatedDeviceObject(socket->ConnectionFileObject); mdl = IoAllocateMdl((PVOID)remainBuf, bytesToGet, FALSE, FALSE, NULL); if(!mdl) { ExFreePool(remainBuf); return; } MmBuildMdlForNonPagedPool(mdl); poCtx = (PCPR_PROCESS_OVERFLOW_CONTEXT)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_PROCESS_OVERFLOW_CONTEXT), CPR_POOL_TAG_OVERFLOW_CONTEXT ); if(!poCtx) { ExFreePool(remainBuf); IoFreeMdl(poCtx->mdl); return; } poCtx->remainBuf = remainBuf; poCtx->socket = socket; poCtx->mdl = mdl; TdiBuildReceive( remainIrp, deviceObject, socket->ConnectionFileObject, CprTdiRemainComplete, poCtx, mdl, TDI_RECEIVE_NORMAL, bytesToGet ); Uart->OverflowSize -= bytesToGet; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); CprReleaseSerialSpinLockFromDpcLevel(Uart->DeviceExtension); status = IoCallDriver(deviceObject, remainIrp); #ifndef IMTESTING if (status == STATUS_PENDING) { KeWaitForSingleObject(&socket->Event, Executive, KernelMode, FALSE, NULL); } #endif CprAcquireSerialSpinLockAtDpcLevel(Uart->DeviceExtension); } } CprDebugPrint2(Uart->DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--. bytesToGet %d OverFlowSize %d", bytesToGet, Uart->OverflowSize); } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartRead // reades data // // Arguments: // IN Uart // uart device extension // // Return Value: // data read // // Comment: // This method is called with SerialLock held // UCHAR CprUartRead( IN PCPR_UART Uart ) { UCHAR data; if (RxDataAvailable(Uart)) { #ifdef SCPR // Is AES turned on? if (Uart->DeviceExtension->AES) { CprDecrypt(Uart->DeviceExtension, Uart->RxReadPtr, &data, 1); } else #endif { data = *Uart->RxReadPtr; } if (++Uart->RxReadPtr >= Uart->RxEndBuffer) { Uart->RxReadPtr = Uart->RxBuffer; // Take care of wrap around. // // Need to wrap write pointer around also. // Otherwise it will look like the buffer is full. // if (Uart->RxWritePtr == Uart->RxEndBuffer) Uart->RxWritePtr = Uart->RxBuffer; } } else { // this routine should not be called if there is no // data available ASSERT(FALSE); data = 0; } if (Uart->OverflowSize > 0) ProcessOverflow(Uart); // if there is no more read data, reset rx data available event if (RxBufferEmpty(Uart)) { Uart->RxDataEvent = FALSE; } return data; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadBlock // reades data // // Arguments: // IN Uart // uart device extension // OUT PUCHAR Buf; // buffer to place read data into // IN ULONG BufSize; // max size of Buf // // Return Value: // number of bytes read // // Comment: // This method is called with SerialLock held // ULONG CprUartReadBlock( IN PCPR_UART Uart, OUT PUCHAR Buf, IN ULONG BufSize ) { ULONG bytesToRead; ULONG rxBytesAtEnd; ULONG rxBytesAtBeg; ULONG bytesProcessed = 0; CprDebugPrint2(Uart->DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. Buf %p BufSize %d", Buf, BufSize); if (RxDataAvailable(Uart)) { // First, read data from the end of the buffer if (Uart->RxWritePtr > Uart->RxReadPtr) { rxBytesAtBeg = 0; rxBytesAtEnd = (ULONG)(Uart->RxWritePtr - Uart->RxReadPtr); } else { rxBytesAtBeg = (ULONG)(Uart->RxWritePtr - Uart->RxBuffer); rxBytesAtEnd = (ULONG)(Uart->RxEndBuffer - Uart->RxReadPtr); } bytesToRead = rxBytesAtEnd; if (bytesToRead > BufSize) bytesToRead = BufSize; #ifdef SCPR // Is AES turned on? if (Uart->DeviceExtension->AES) { CprDecrypt(Uart->DeviceExtension, Uart->RxReadPtr, Buf, bytesToRead); } else #endif { RtlCopyMemory(Buf, Uart->RxReadPtr, bytesToRead); } // Update read pointer. Uart->RxReadPtr += bytesToRead; if (Uart->RxReadPtr == Uart->RxEndBuffer) { Uart->RxReadPtr = Uart->RxBuffer; // Take care of wrap around. // // Need to wrap write pointer around also. // Otherwise it will look like the buffer is full. // if (Uart->RxWritePtr == Uart->RxEndBuffer) Uart->RxWritePtr = Uart->RxBuffer; } bytesProcessed = bytesToRead; // Is there more data and more room? if ((bytesProcessed != BufSize) && RxDataAvailable(Uart)) { Buf += bytesProcessed; BufSize -= bytesProcessed; bytesToRead = rxBytesAtBeg; if (bytesToRead > BufSize) bytesToRead = BufSize; #ifdef SCPR // Is AES turned on? if (Uart->DeviceExtension->AES) { CprDecrypt(Uart->DeviceExtension, Uart->RxReadPtr, Buf, bytesToRead); } else #endif { RtlCopyMemory(Buf, Uart->RxReadPtr, bytesToRead); } // Update read pointer. Uart->RxReadPtr += bytesToRead; // No Wrap arround test needed bytesProcessed += bytesToRead; } } else { // this routine should not be called if there is no // data available //DbgPrint("CprUartReadBlock: Assert\n"); //DbgBreakPoint(); ASSERT(FALSE); } // // If data came in from CprTdiEventReceive and there was not room in the buffer // The data is read but CprTdiEventReceive was stalled // if there is now room, copy data from OverflowBuffer to Uart Buffer. // if (Uart->OverflowSize > 0) ProcessOverflow(Uart); // if there is no more read data, reset rx data available event if (RxBufferEmpty(Uart)) { Uart->RxDataEvent = FALSE; } CprDebugPrint1(Uart->DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. bytesProcessed %d", bytesProcessed); return bytesProcessed; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartStartWrite // restart transmit engine // // Arguments: // IN Uart // uart device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprUartStartWrite( IN PCPR_UART Uart ) { Uart->TxEmptyEvent = TRUE; Uart->DeviceExtension->TxIdle = FALSE; CprUartCheckEvents(Uart); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadIIR // read interrupt id register // // Arguments: // IN Uart // uart device extension // // Return Value: // Interrupt ID register // // Comment: // This method is called with SerialLock held // UCHAR CprUartReadIIR( IN PCPR_UART Uart ) { UCHAR iir; // check for pending events in the // interrupt priority order if (Uart->LineStatusEvent) { iir = CPR_UART_IIR_RLS; } else if (Uart->RxDataEvent) { iir = CPR_UART_IIR_RDA; } else if (Uart->TxEmptyEvent) { iir = CPR_UART_IIR_THR; Uart->TxEmptyEvent = FALSE; } else if (Uart->ModemStatusEvent) { iir = CPR_UART_IIR_MS; } else { iir = CPR_UART_IIR_NO_INTERRUPT_PENDING; } return iir; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadLSR // read line status register // // Arguments: // IN Uart // uart device extension // // Return Value: // line status register // // Comment: // This method is called with SerialLock held // UCHAR CprUartReadLSR( IN PCPR_UART Uart ) { UCHAR lsr; Uart->LineStatusEvent = FALSE; lsr = Uart->Lsr; if (RxDataAvailable(Uart)) { lsr |= CPR_UART_LSR_DR; } else { lsr &= ~CPR_UART_LSR_DR; } //***************************************************************** //***************************************************************** // TODO: modify following bits to match // error state // DAG: Not sure what this is. //***************************************************************** //***************************************************************** //lsr &= ~CPR_UART_LSR_OE; // Overflow Error //lsr &= ~CPR_UART_LSR_PE; // Parity Error //lsr &= ~CPR_UART_LSR_FE; // Framing Error //lsr &= ~CPR_UART_LSR_BI; // Break Indicator Error //lsr &= ~CPR_UART_LSR_FIFOERR; // FIFO Error //***************************************************************** //***************************************************************** // TODO: modify following bits to match // transmitter state // DAG: Not sure what this is. //***************************************************************** //***************************************************************** //lsr |= CPR_UART_LSR_THRE; // Transmitter Idle //lsr |= CPR_UART_LSR_TEMT; // Transmitter Empty if (Uart->DeviceExtension->TxIdle) { lsr |= CPR_UART_LSR_THRE; // Transmitter Idle lsr |= CPR_UART_LSR_TEMT; // Transmitter Empty } else { lsr &= ~CPR_UART_LSR_THRE; // Transmitting still going on lsr &= ~CPR_UART_LSR_TEMT; // Transmitting still going on } return lsr; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadMSR // read modem status register // // Arguments: // IN Uart // uart device extension // // Return Value: // modem status register // // Comment: // This method is called with SerialLock held // UCHAR CprUartReadMSR( IN PCPR_UART Uart ) { UCHAR msr; msr = Uart->Msr; // reading modem status reset the following bits Uart->Msr &= ~CPR_UART_MSR_DCTS; Uart->Msr &= ~CPR_UART_MSR_DDSR; Uart->Msr &= ~CPR_UART_MSR_TERI; Uart->Msr &= ~CPR_UART_MSR_DDCD; Uart->ModemStatusEvent = FALSE; return msr; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadMCR // read modem control register // // Arguments: // IN Uart // uart device extension // // Return Value: // modem control register // // Comment: // This method is called with SerialLock held // UCHAR CprUartReadMCR( IN PCPR_UART Uart ) { return Uart->Mcr; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWriteMCR // write modem control register // // Arguments: // IN Uart // uart device extension // // IN Mcr // new modem control value // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprUartWriteMCR( IN PCPR_UART Uart, IN UCHAR Mcr ) { PCPR_DEVICE_EXTENSION devExt = Uart->DeviceExtension; if (devExt->UseRFC2217) { if ((Mcr & CPR_UART_MCR_RTS) && !(Uart->Mcr & CPR_UART_MCR_RTS)) { CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_RTS_ON); } else if (!(Mcr & CPR_UART_MCR_RTS) && (Uart->Mcr & CPR_UART_MCR_RTS)) { CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_RTS_OFF); } if ((Mcr & CPR_UART_MCR_DTR) && !(Uart->Mcr & CPR_UART_MCR_DTR)) { CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_DTR_ON); } else if (!(Mcr & CPR_UART_MCR_DTR) && (Uart->Mcr & CPR_UART_MCR_DTR)) { CprRfc2217_SendCPCByteCommand(devExt, TNCAS_SET_CONTROL, TN_CONTROL_DTR_OFF); } if (!IsBufferEmpty(&devExt->ToNetBuf)) { CprRfc2217_SendToNet(devExt, TRUE); } } // else // { // // check for RTS signal // // in the following code RTS is connected to CTS (like NULL-Modem) // if (Mcr & CPR_UART_MCR_RTS) // { // if (!(Uart->Msr & CPR_UART_MSR_CTS)) // { // Uart->Msr |= CPR_UART_MSR_CTS; // Uart->Msr |= CPR_UART_MSR_DCTS; // Uart->ModemStatusEvent = TRUE; // } // } // else // { // if (Uart->Msr & CPR_UART_MSR_CTS) // { // Uart->Msr &= ~CPR_UART_MSR_CTS; // Uart->Msr |= CPR_UART_MSR_DCTS; // Uart->ModemStatusEvent = TRUE; // } // } // // // check for DTR signal // if (Mcr & CPR_UART_MCR_DTR) // { //#if 1 // if (!(Uart->Msr & CPR_UART_MSR_DSR)) // { // Uart->Msr |= CPR_UART_MSR_DSR; // Uart->Msr |= CPR_UART_MSR_DDSR; // Uart->Msr |= CPR_UART_MSR_DCD; // Uart->Msr |= CPR_UART_MSR_DDCD; // Uart->ModemStatusEvent = TRUE; // } // } // else // { // if (Uart->Msr & CPR_UART_MSR_DSR) // { // Uart->Msr &= ~CPR_UART_MSR_DSR; // Uart->Msr |= CPR_UART_MSR_DDSR; // Uart->Msr &= ~CPR_UART_MSR_DCD; // Uart->Msr |= CPR_UART_MSR_DDCD; // Uart->ModemStatusEvent = TRUE; // } //#endif // } // } // save new mcr value Uart->Mcr = Mcr; // check if changing mcr value generated // any events CprUartCheckEvents(Uart); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartReadLCR // read line control register // // Arguments: // IN Uart // uart device extension // // Return Value: // Line control register // // Comment: // This method is called with SerialLock held // UCHAR CprUartReadLCR( IN PCPR_UART Uart ) { return Uart->Lcr; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWriteLCR // write line control register // // Arguments: // IN Uart // uart device extension // // IN Lcr // new line control value // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprUartWriteLCR( IN PCPR_UART Uart, IN UCHAR Lcr ) { UCHAR SaveLCR = Uart->Lcr; UCHAR DataSize; UCHAR Parity; UCHAR StopSize; char Msg[CPR_EVENT_MSG_SIZE]; Uart->Lcr = Lcr; if (Uart->DeviceExtension->UseRFC2217) { if (((SaveLCR & CPR_UART_LCR_DATA_MASK) != (Lcr & CPR_UART_LCR_DATA_MASK)) || (Uart->DeviceExtension->DataSizeSent == FALSE)) { Uart->DeviceExtension->DataSizeSent = TRUE; DataSize = CprRfc2217_GetPortDataSize(Uart->DeviceExtension); CprRfc2217_SendCPCByteCommand(Uart->DeviceExtension, TNCAS_SET_DATASIZE, DataSize); } if (((SaveLCR & CPR_UART_LCR_PARITY_MASK) != (Lcr & CPR_UART_LCR_PARITY_MASK)) || (Uart->DeviceExtension->ParitySent == FALSE)) { Uart->DeviceExtension->ParitySent = TRUE; Parity = CprRfc2217_GetPortParity(Uart->DeviceExtension); CprRfc2217_SendCPCByteCommand(Uart->DeviceExtension, TNCAS_SET_PARITY, Parity); } if (((SaveLCR & CPR_UART_LCR_STOP_MASK) != (Lcr & CPR_UART_LCR_STOP_MASK)) || (Uart->DeviceExtension->StopSent == FALSE)) { Uart->DeviceExtension->StopSent = TRUE; StopSize = CprRfc2217_GetPortStopSize(Uart->DeviceExtension); CprRfc2217_SendCPCByteCommand(Uart->DeviceExtension, TNCAS_SET_STOPSIZE, StopSize); } if ((SaveLCR & CPR_UART_LCR_BREAK) != (Lcr & CPR_UART_LCR_BREAK)) { // There's a BREAK change if (Lcr & CPR_UART_LCR_BREAK) { // BREAK ON CprRfc2217_SendCPCByteCommand(Uart->DeviceExtension, TNCAS_SET_CONTROL, TN_CONTROL_BREAK_ON); } else { // BREAK OFF CprRfc2217_SendCPCByteCommand(Uart->DeviceExtension, TNCAS_SET_CONTROL, TN_CONTROL_BREAK_OFF); } } if (!IsBufferEmpty(&Uart->DeviceExtension->ToNetBuf)) { CprRfc2217_SendToNet(Uart->DeviceExtension, TRUE); } } return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartWriteIER // write interrupt enable register // // Arguments: // IN Uart // uart device extension // // IN Ier // new interrupt enabled value // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprUartWriteIER( IN PCPR_UART Uart, IN UCHAR Ier ) { Uart->Ier = Ier; CprUartCheckEvents(Uart); return; }