// backdoor.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "backdoor.tmh" #endif ULONG dmy = 1; #ifdef GENERIC TCHAR deviceLinkBuffer[] = _T("\\DosDevices\\GCPR"); TCHAR deviceNameBuffer[] = _T("\\Device\\Gcpr"); #elif SCPR TCHAR deviceLinkBuffer[] = _T("\\DosDevices\\SCPR"); TCHAR deviceNameBuffer[] = _T("\\Device\\Scpr"); #else TCHAR deviceLinkBuffer[] = _T("\\DosDevices\\CPR"); TCHAR deviceNameBuffer[] = _T("\\Device\\Cpr"); #endif char *IoctlToString(ULONG ioCode); /////////////////////////////////////////////////////////////////////////////////////////////////// // CprInitBackdoorDevice // // Arguments: // IN DriverObject // // Return Value: // NT status code // NTSTATUS CprInitBackdoorDevice (PDRIVER_OBJECT DriverObject) { PDEVICE_OBJECT deviceObject = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING deviceNameUnicodeString; PBACKDOOR_DEVICE_EXTENSION backdoorDeviceExt; PCPR_DEVICE_EXTENSION serialDeviceExt; UNICODE_STRING deviceLinkUnicodeString; UNICODE_STRING comPort; int i; CprDebugPrint(NULL, DBG_PNP, DBG_TRACE, __FUNCTION__"++"); RtlInitUnicodeString(&deviceNameUnicodeString, deviceNameBuffer); /* Create an EXCLUSIVE device, i.e. only 1 thread at a time can send i/o requests. */ ntStatus = IoCreateDevice ( DriverObject, sizeof (BACKDOOR_DEVICE_EXTENSION), &deviceNameUnicodeString, FILE_DEVICE_CPR, 0, FALSE, /* do not allow multiple threads to send I/O requests at the same time */ &deviceObject ); if (NT_SUCCESS(ntStatus)) { g_Data.BackdoorDevice = deviceObject; backdoorDeviceExt = (PBACKDOOR_DEVICE_EXTENSION)deviceObject->DeviceExtension; /* This controlls how we do reads and writes */ // Maybe try direct IO and use MDLs deviceObject->Flags |= DO_BUFFERED_IO; /* Set up synchronization objects, state info,, etc. */ RtlZeroMemory (backdoorDeviceExt, sizeof (*backdoorDeviceExt)); backdoorDeviceExt->numPorts = 0; backdoorDeviceExt->opened = 0; /* Create a symbolic link that Win32 apps can specify to gain access to this driver/device */ RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer); ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString, &deviceNameUnicodeString); if (!NT_SUCCESS(ntStatus)) { CprDebugPrint(NULL, DBG_PNP, DBG_INFO, __FUNCTION__": IoCreateSymbolicLink failed!"); } } if (!NT_SUCCESS(ntStatus)) { /* Something went wrong, so clean up (free resources, etc.) */ CprDebugPrint1(NULL, DBG_PNP, DBG_INFO, __FUNCTION__": Something went wrong! STATUS %x", ntStatus); if (deviceObject) { g_Data.BackdoorDevice = NULL; IoDeleteDevice (deviceObject); } } CprDebugPrint(NULL, DBG_PNP, DBG_TRACE, __FUNCTION__"--"); return ntStatus; } VOID CprDeleteBackdoorDevice() { UNICODE_STRING deviceLinkUnicodeString; if (g_Data.BackdoorDevice != NULL) { IoDeleteDevice(g_Data.BackdoorDevice); RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer); IoDeleteSymbolicLink (&deviceLinkUnicodeString); g_Data.BackdoorDevice = NULL; } } NTSTATUS CprBackdoorIoctl (PDEVICE_OBJECT DeviceObject, PIRP Irp) { PBACKDOOR_DEVICE_EXTENSION bdExt; PDEVICE_OBJECT serialDev; PCPR_DEVICE_EXTENSION serialExt; NTSTATUS Status = STATUS_SUCCESS; PBdParams pBdParams = NULL; PBdParams_32 pBdParams32 = NULL; BOOLEAN release = TRUE; ULONG portIndex = 0; PIO_STACK_LOCATION irpStack; KIRQL oldIrql; ULONG ioCode; ULONG *inBufLen; ULONG *outBufLen; PCHAR inBuf; // pointer to Input and output buffer PMDL mdl = NULL; __try { // Get our IRP stack location irpStack = IoGetCurrentIrpStackLocation(Irp); ioCode = irpStack->Parameters.DeviceIoControl.IoControlCode; bdExt = (PBACKDOOR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; Irp->IoStatus.Information = 0; inBufLen = &irpStack->Parameters.DeviceIoControl.InputBufferLength; outBufLen = &irpStack->Parameters.DeviceIoControl.OutputBufferLength; CprDebugPrint1(NULL, DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); CprDebugPrint2(NULL, DBG_IO, DBG_INFO, __FUNCTION__": IOCODE %X %s", ioCode, IoctlToString(ioCode)); // functions are 12 bits (0xFFF) if ( ((ioCode >> 2) & 0xFFF) <= 100) { ULONG SizeofBdParams = sizeof(BdParams); #if defined(_WIN64) if (IoIs32bitProcess( Irp )) SizeofBdParams = sizeof(BdParams_32); #endif // ===================================================================== // These are port specific IOCTL codes // ===================================================================== if (*inBufLen != SizeofBdParams) { Status = STATUS_BUFFER_TOO_SMALL; *inBufLen = SizeofBdParams; } else { #if defined(_WIN64) if (IoIs32bitProcess( Irp )) { pBdParams32 = (PBdParams_32)Irp->AssociatedIrp.SystemBuffer; portIndex = pBdParams32->portIndex; } else #endif { pBdParams = (PBdParams)Irp->AssociatedIrp.SystemBuffer; portIndex = pBdParams->portIndex; } if ((portIndex == 0) || (portIndex > MAX_PORTS)) { Status = STATUS_INVALID_PARAMETER; *inBufLen = SizeofBdParams; } else { serialDev = (PDEVICE_OBJECT)bdExt->serialDevice[portIndex]; if (!serialDev) { Status = STATUS_INVALID_PARAMETER; *inBufLen = SizeofBdParams; } else { serialExt = (PCPR_DEVICE_EXTENSION)serialDev->DeviceExtension; switch (ioCode) { case CPR_IOCTL_RELOAD_REGISTRY: RtlZeroMemory(serialExt->Validated, sizeof(BOOLEAN) * MAX_SERVICES); //serialExt->Validated = FALSE; CprDebugPrint(serialExt, DBG_IO, DBG_INFO, __FUNCTION__": CPR_IOCTL_RELOAD_REGISTRY"); CprReadRegistry(serialExt); break; case CPR_IOCTL_CLOSE_PORT: //DbgPrint("DAG: CPR_IOCTL_CLOSE_PORT\n"); CprCleanupPort(serialExt, NULL); CprClosePort(serialExt); break; case CPR_IOCTL_DISCONNECT_NETWORK: //DbgPrint("DAG: CPR_IOCTL_DISCONNECT_NETWORK\n"); if (serialExt->ListenMode == LISTEN_MODE_NONE) { CprCleanupPort(serialExt, NULL); CprClosePort(serialExt); } { SOCKET connectSocket; CprAcquireSerialSpinLock(serialExt, &oldIrql); connectSocket = serialExt->socket; serialExt->socket = NULL; CprReleaseSerialSpinLock(serialExt, oldIrql); if (connectSocket != NULL) { CprTdiDisconnect(connectSocket, FALSE, NULL, NULL); CprTdiFreeConnectSocket(connectSocket); NetworkStatusChange(serialExt, CPR_NETWORK_STATUS_DISCONNECTED); } if (serialExt->ListenMode == LISTEN_MODE_AUTO) { NetworkStatusChange(serialExt, CPR_NETWORK_STATUS_LISTENING); } } break; case CPR_IOCTL_GET_PORT_INFO: { if (pBdParams32 && (pBdParams32->bufSize != sizeof(PortInfo))) { CprDebugPrint2(serialExt, DBG_IO, DBG_ERR, __FUNCTION__": CPR_IOCTL_GET_PORT_INFO: Buffer too small. passed in: %d, should be %d", pBdParams32->bufSize, sizeof(PortInfo)); Status = STATUS_BUFFER_TOO_SMALL; pBdParams32->bufSize = sizeof(PortInfo); } else if (pBdParams && (pBdParams->bufSize != sizeof(PortInfo))) { CprDebugPrint2(serialExt, DBG_IO, DBG_ERR, __FUNCTION__": CPR_IOCTL_GET_PORT_INFO: Buffer too small. passed in: %d, should be %d", pBdParams->bufSize, sizeof(PortInfo)); Status = STATUS_BUFFER_TOO_SMALL; pBdParams->bufSize = sizeof(PortInfo); } else { ULONG i; PPortInfo pPortInfo; size_t aesSize = sizeof(serialExt->AESKey); if (pBdParams32) pPortInfo = (PPortInfo)pBdParams32->buffer; else pPortInfo = (PPortInfo)pBdParams->buffer; RtlZeroMemory (pPortInfo, sizeof(PortInfo)); pPortInfo->portNumber = serialExt->portNumber; RtlStringCchPrintfW( pPortInfo->portName, sizeof(pPortInfo->portName)/sizeof((pPortInfo->portName)[0]), _T("COM%d"), serialExt->portNumber); RtlCopyMemory(pPortInfo->AESKey, serialExt->AESKey, sizeof(serialExt->AESKey)); pPortInfo->AES = serialExt->AES; pPortInfo->AESKeyLength = serialExt->AESKeyLength; pPortInfo->AutoReconErr = serialExt->AutoReconErr; pPortInfo->AutoReconPeer = serialExt->AutoReconPeer; pPortInfo->CnTmo = serialExt->CnTmo; pPortInfo->NoDiscon = serialExt->NoDiscon; pPortInfo->ReconLimit = serialExt->ReconLimit; pPortInfo->UseRFC2217 = serialExt->UseRFC2217; pPortInfo->DtrConnection = serialExt->DtrConnection; pPortInfo->WaitOnWrite = serialExt->WaitOnWrite; pPortInfo->BufferWrites = serialExt->BufferWrites; pPortInfo->TransmitEmpty = serialExt->TransmitEmpty; pPortInfo->ListenMode = serialExt->ListenMode; pPortInfo->KeepAliveOnOff = serialExt->KeepAliveOnOff; pPortInfo->KeepAliveTime = serialExt->KeepAliveTime; pPortInfo->KeepAliveInterval = serialExt->KeepAliveInterval; pPortInfo->NumServices = serialExt->NumServices; for (i = 0 ; (i < serialExt->NumServices) && (i < MAX_SERVICES); i++) { pPortInfo->Services[i].Type = serialExt->Services[i].Type; pPortInfo->Services[i].Port = serialExt->Services[i].Port; RtlCopyMemory(pPortInfo->Services[i].Address, serialExt->Services[i].Address, sizeof(serialExt->Services[i].Address)); } } break; } case CPR_IOCTL_GET_PORT_STATUS: { if (pBdParams32 && (pBdParams32->bufSize != sizeof(PortStatus))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams32->bufSize = sizeof(PortStatus); } else if (pBdParams && (pBdParams->bufSize != sizeof(PortStatus))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams->bufSize = sizeof(PortStatus); } else { // Acquire Session Queue because ComStatus Changes or // Network Status Changes could happen simulataneously // to this IOCTL. PPortStatus pPortStatus; PCPR_SERVICE pCurService = &serialExt->Services[serialExt->CurService]; if (pBdParams32) pPortStatus = (PPortStatus)pBdParams32->buffer; else pPortStatus = (PPortStatus)pBdParams->buffer; KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); RtlZeroMemory (pPortStatus, sizeof(PortStatus)); pPortStatus->portNumber = serialExt->portNumber; pPortStatus->status = serialExt->ComStatus; pPortStatus->networkStatus = serialExt->NetworkStatus; if ((serialExt->ListenMode != LISTEN_MODE_NONE) && (serialExt->NetworkStatus != CPR_NETWORK_STATUS_LISTENING)) { pPortStatus->Port = htons(serialExt->ListenMode_sin_port); inet_ntow( serialExt->ListenMode_in_addr, pPortStatus->Address, sizeof(pPortStatus->Address) / sizeof(WCHAR)); } else { pPortStatus->Port = pCurService->Port; RtlCopyMemory(pPortStatus->Address, pCurService->Address, sizeof(pCurService->Address)); } ComStatusClear(serialExt->portNumber); KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); } break; } case CPR_IOCTL_GET_PORT_DEVICE: { if (pBdParams32 && (pBdParams32->bufSize != sizeof(CprPortDevice))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams32->bufSize = sizeof(CprPortDevice); } else if (pBdParams && (pBdParams->bufSize != sizeof(CprPortDevice))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams->bufSize = sizeof(CprPortDevice); } else { ULONG service; KIRQL oldIrql; PCprPortDevice pCPD; if (pBdParams32) pCPD = (PCprPortDevice)pBdParams32->buffer; else pCPD = (PCprPortDevice)pBdParams->buffer; for (service = 0; service < serialExt->NumServices; service++) { char addrStr[16]; int n; for (n = 0; n < 16; n++) addrStr[n] = (char)serialExt->Services[ service ].Address[n]; if (CprUartUdpConfigPorts(&serialExt->Uart, inet_addr(addrStr)) == STATUS_SUCCESS) { break; } } // id and macAddr will be empty if unsuccessful. pCPD->id[0] = serialExt->DeviceId[0]; pCPD->id[1] = serialExt->DeviceId[1]; pCPD->id[2] = serialExt->DeviceId[2]; pCPD->id[3] = serialExt->DeviceId[3]; pCPD->macAddr[0] = serialExt->MacAddress[0]; pCPD->macAddr[1] = serialExt->MacAddress[1]; pCPD->macAddr[2] = serialExt->MacAddress[2]; pCPD->macAddr[3] = serialExt->MacAddress[3]; pCPD->macAddr[4] = serialExt->MacAddress[4]; pCPD->macAddr[5] = serialExt->MacAddress[5]; } break; } case CPR_IOCTL_SET_PORT_INFO: { // Use output buffer because pBdParams uses input buffer. if (pBdParams32 && (pBdParams32->bufSize != sizeof(PortInfo))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams32->bufSize = sizeof(PortInfo); } else if (pBdParams && (pBdParams->bufSize != sizeof(PortInfo))) { Status = STATUS_BUFFER_TOO_SMALL; pBdParams->bufSize = sizeof(PortInfo); } else { PPortInfo pPortInfo = (PPortInfo)pBdParams->buffer; if (pBdParams32) pPortInfo = (PPortInfo)pBdParams32->buffer; else pPortInfo = (PPortInfo)pBdParams->buffer; RtlZeroMemory(serialExt->Validated, sizeof(BOOLEAN) * MAX_SERVICES); //serialExt->Validated = FALSE; RtlCopyMemory(serialExt->AESKey, pPortInfo->AESKey, sizeof(serialExt->AESKey)); serialExt->AES = pPortInfo->AES; serialExt->AESKeyLength = pPortInfo->AESKeyLength; serialExt->AutoReconErr = pPortInfo->AutoReconErr; serialExt->AutoReconPeer = pPortInfo->AutoReconPeer; serialExt->CnTmo = pPortInfo->CnTmo; serialExt->NoDiscon = pPortInfo->NoDiscon; serialExt->NumServices = pPortInfo->NumServices; serialExt->ReconLimit = pPortInfo->ReconLimit; serialExt->UseRFC2217 = pPortInfo->UseRFC2217; serialExt->DtrConnection = pPortInfo->DtrConnection; serialExt->WaitOnWrite = pPortInfo->WaitOnWrite; serialExt->BufferWrites = pPortInfo->BufferWrites; serialExt->TransmitEmpty = pPortInfo->TransmitEmpty; serialExt->ListenMode = pPortInfo->ListenMode; serialExt->KeepAliveOnOff = pPortInfo->KeepAliveOnOff; serialExt->KeepAliveTime = pPortInfo->KeepAliveTime; serialExt->KeepAliveInterval = pPortInfo->KeepAliveInterval; } break; } default: Status = STATUS_INVALID_PARAMETER; break; } } } } } else { // ===================================================================== // These are general non-port specific IOCTL codes // codes 101 and up. // ===================================================================== switch(ioCode) { case CPR_IOCTL_UPDATE_DRIVER: g_Data.updateDriver = *((BOOLEAN*)Irp->AssociatedIrp.SystemBuffer); break; case CPR_IOCTL_GET_VERSION: { ULONG Len; ULONG OutLen; Status = RtlStringCchLengthA(CPR_DRVR_VERSION, 40, (size_t*)&Len); if (Status == STATUS_SUCCESS) { OutLen = *outBufLen; if (OutLen < (Len+1)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = Len+1; } else { char *str = (char*)Irp->AssociatedIrp.SystemBuffer; Status = RtlStringCchCopyA(str, Len+1, CPR_DRVR_VERSION); Irp->IoStatus.Information = Len + 1; } } break; } case CPR_IOCTL_EVENT_READ: if (*outBufLen != sizeof(CPR_EVENT_LOG)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(CPR_EVENT_LOG); } else { // // if there is no session, create it and use it. // CprDebugPrint2(NULL, DBG_PNP, DBG_INFO, " ===> Irp %p SystemBuffer %p", Irp, Irp->AssociatedIrp.SystemBuffer); Status = BackdoorEventLogRead(Irp); if (Status == STATUS_PENDING) { release = FALSE; } } break; case CPR_IOCTL_STATUS_READ: if (*outBufLen != sizeof(PortStatus)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(PortStatus); } else { Status = BackdoorEventLogRead(Irp); if (Status == STATUS_PENDING) release = FALSE; } break; case CPR_IOCTL_SET_EVENT_LOG_BUFFER: inBuf = *((PCHAR*)Irp->AssociatedIrp.SystemBuffer); try { // // Before accessing user buffer, se must probe for read/write // to make sure the buffer is indeed an userbuffer with proper access // rights and length. ProbeForRead/Write will raise an exception // if it's otherwise. // ProbeForRead( inBuf, *inBufLen, sizeof( UCHAR ) ); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); //SIOCTL_KDPRINT(( // "Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n", // ntStatus)); break; } // // We should map the buffer in the system process address space. // First allocate an MDL large enough to describe the buffer // and initialize it. Please note that on a x86 system, the maximum // size of a buffer that an MDL can describe is 65508 KB. // mdl = IoAllocateMdl(inBuf, *inBufLen, FALSE, TRUE, NULL); if(!mdl) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } try { // // Probe and lock the pages of this buffer in physical memory. // We can specify IoReadAccess, IoWriteAccess or IoModifyAccess // Always perform this operation in a try except block. // MmProbeAndLockPages will raise an exception if it fails. // MmProbeAndLockPages(mdl, KernelMode, IoModifyAccess); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IoFreeMdl(mdl); break; } // // Map the physical pages described by the MDL into system space. // Note: double mapping the buffer this way causes lot of // system overhead for large size buffers. // pEventLogBuffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority); if (!pEventLogBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; MmUnlockPages(mdl); IoFreeMdl(mdl); break; } break; case CPR_IOCTL_CLEAR_EVENT_LOG_BUFFER: pEventLogBuffer = NULL; break; case CPR_IOCTL_EVENT_LOG_WAIT: // DAG TODO: I don't think this IOCTL is used. if (pEventLogBuffer) { PCPR_EVENT_LOG_HEADER hdr = &pEventLogBuffer->header; if (EventLogFull(hdr)) { // FULL } else { pEventLogBuffer->eventLogs[hdr->writeNdx].comPort = (short)dmy++; IncWritePtr(hdr); } } break; case CPR_IOCTL_START_EVENT_READ: { PCPR_SESSION pSession; pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (!pSession) pSession = CreateSession(TRUE); if (pSession) { if (pSession->EventLogActive == TRUE) Status = STATUS_DEVICE_ALREADY_ATTACHED; else pSession->EventLogActive = TRUE; } } break; case CPR_IOCTL_CANCEL_EVENT_READ: { // Last TRUE parameter tells CprFindSession // to remove the session if found. // __try { PCPR_SESSION pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (pSession) { pSession->EventLogActive = FALSE; KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); if (pSession->EventLogIrp != NULL) { PIRP pIrp = pSession->EventLogIrp; pSession->EventLogIrp = NULL; if (IoSetCancelRoutine (pIrp, NULL)) { PCPR_EVENT_LOG pEvtLogFromApp = (PCPR_EVENT_LOG)pIrp->AssociatedIrp.SystemBuffer; RtlZeroMemory (pEvtLogFromApp, sizeof (CPR_EVENT_LOG)); pEvtLogFromApp->status = STATUS_CANCELLED; pEvtLogFromApp->flags = CPR_EVENT_FLAG_CANCELLED; pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = sizeof(CPR_EVENT_LOG); IoCompleteRequest (pIrp, IO_NO_INCREMENT); } } KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); CprFlushEventLogQueue(&pSession->EventLogQueue); if (pSession->ComStatusIrp == NULL) { // Find and DeQueue pSession = CprFindSession(&gSessionQueue, GetSessionId(), TRUE, TRUE); if (pSession) CprCleanUpSession(pSession); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { } } break; case CPR_IOCTL_GET_FILTER_DATA: if (*outBufLen < sizeof(CPR_FILTER_DATA)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(CPR_FILTER_DATA); } else { // Find Session but keep in queue. PCPR_SESSION pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (pSession) { memcpy(Irp->AssociatedIrp.SystemBuffer, &pSession->FilterData, sizeof(CPR_FILTER_DATA)); } } break; case CPR_IOCTL_SET_FILTER_DATA: if (*inBufLen < sizeof(CPR_FILTER_DATA)) { Status = STATUS_BUFFER_TOO_SMALL; *inBufLen = sizeof(CPR_FILTER_DATA); } else { // Find Session but keep in queue. PCPR_SESSION pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (pSession) { memcpy(&pSession->FilterData, Irp->AssociatedIrp.SystemBuffer, sizeof(CPR_FILTER_DATA)); } } break; case CPR_IOCTL_CLR_FILTER_DATA: { // Clear Filter Data Here // Find Session but keep in queue. PCPR_SESSION pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (pSession) { RtlZeroMemory(&pSession->FilterData, sizeof(CPR_FILTER_DATA)); } } break; case CPR_IOCTL_EVENT_SEND_DEBUG: CprLogEvent( CPR_EVENT_TYPE_DEBUG, CPR_EVENT_SUB_TYPE_NONE, NULL, Status, "This is a test message"); break; case CPR_IOCTL_SET_EVENT_LOG_FILTER: //if (*inBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *inBufLen = sizeof(ULONG); //} //else //{ // CprEventLogFilter = *((ULONG*)Irp->AssociatedIrp.SystemBuffer); //} break; case CPR_IOCTL_CLEAR_EVENT_LOG_FILTER: //CprEventLogFilter = CPR_EVENT_TYPE_NONE; break; case CPR_IOCTL_GET_EVENT_LOG_FILTER: //if (*outBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *outBufLen = sizeof(ULONG); //} //else //{ // ULONG *eventLogFilter = (ULONG*)Irp->AssociatedIrp.SystemBuffer; // *eventLogFilter = CprEventLogFilter; // Irp->IoStatus.Information = sizeof(ULONG); //} break; case CPR_IOCTL_SET_EVENT_LOG_IOCTL_FILTER: //if (*inBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *inBufLen = sizeof(ULONG); //} //else //{ // CprELIoctlFilter = *((ULONG*)Irp->AssociatedIrp.SystemBuffer); //} break; case CPR_IOCTL_CLEAR_EVENT_LOG_IOCTL_FILTER: //CprELIoctlFilter = CPR_EVENT_TYPE_NONE; break; case CPR_IOCTL_GET_EVENT_LOG_IOCTL_FILTER: //if (*outBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *outBufLen = sizeof(ULONG); //} //else //{ // ULONG *eventLogIoctlFilter = (ULONG*)Irp->AssociatedIrp.SystemBuffer; // *eventLogIoctlFilter = CprELIoctlFilter; // Irp->IoStatus.Information = sizeof(ULONG); //} break; case CPR_IOCTL_SET_DEBUG_LEVEL: if (*inBufLen < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; *inBufLen = sizeof(ULONG); } else { g_DebugLevel = *((ULONG*)Irp->AssociatedIrp.SystemBuffer); } break; case CPR_IOCTL_GET_DEBUG_LEVEL: if (*outBufLen < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(ULONG); } else { ULONG *debugLevel = (ULONG*)Irp->AssociatedIrp.SystemBuffer; *debugLevel = g_DebugLevel; Irp->IoStatus.Information = sizeof(ULONG); } break; case CPR_IOCTL_SET_EVENT_FLAGS: //if (*inBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *inBufLen = sizeof(ULONG); //} //else //{ // CprEventFlags = *((ULONG*)Irp->AssociatedIrp.SystemBuffer); //} break; case CPR_IOCTL_GET_EVENT_FLAGS: //if (*outBufLen < sizeof(ULONG)) //{ // Status = STATUS_BUFFER_TOO_SMALL; // *outBufLen = sizeof(ULONG); //} //else //{ // ULONG *eventFlags = (ULONG*)Irp->AssociatedIrp.SystemBuffer; // *eventFlags = CprEventFlags; // Irp->IoStatus.Information = sizeof(ULONG); //} break; case CPR_IOCTL_SET_DEBUG_AREA: if (*inBufLen < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; *inBufLen = sizeof(ULONG); } else { g_DebugArea = *((ULONG*)Irp->AssociatedIrp.SystemBuffer); } break; case CPR_IOCTL_GET_DEBUG_AREA: if (*outBufLen < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(ULONG); } else { ULONG *debugArea = (ULONG*)Irp->AssociatedIrp.SystemBuffer; *debugArea = g_DebugArea; Irp->IoStatus.Information = sizeof(ULONG); } break; case CPR_IOCTL_FLUSH_EVENT_LOG_QUEUE: //CprFlushEventLogQueue(&bdExt->EventLogQueue); break; case CPR_IOCTL_GET_PERF_COUNTER: if (*outBufLen < sizeof(LARGE_INTEGER)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(LARGE_INTEGER); } else { LARGE_INTEGER *perfCntr = (LARGE_INTEGER*)Irp->AssociatedIrp.SystemBuffer; *perfCntr = KeQueryPerformanceCounter(NULL); Irp->IoStatus.Information = sizeof(LARGE_INTEGER); } break; case CPR_IOCTL_GET_PERF_FREQ: if (*outBufLen < sizeof(LARGE_INTEGER)) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(LARGE_INTEGER); } else { LARGE_INTEGER *perfFreq = (LARGE_INTEGER*)Irp->AssociatedIrp.SystemBuffer; KeQueryPerformanceCounter(perfFreq); Irp->IoStatus.Information = sizeof(LARGE_INTEGER); } break; case CPR_IOCTL_GET_COM_STATUS: // Returns status right now. if (*outBufLen < sizeof(ULONG) * NUM_COM_ULONGS) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(ULONG) * NUM_COM_ULONGS; } else { #ifdef USE_COM_STATUS_LIST CprGetComStatus(Irp, FALSE); #else KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); CopyComStatus((ULONG*)Irp->AssociatedIrp.SystemBuffer); Irp->IoStatus.Information = sizeof(ULONG) * NUM_COM_ULONGS; KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); #endif } break; case CPR_IOCTL_GET_COM_STATUS_WAIT: // Returns status right now if the status passed in // is different than the current status. Otherwise, // PENDING is returned and this IRP will be completed // either when the status is changed or the // CPR_IOCTL_CANCEL_COM_STATUS_WAIT IRP is received. // if (*outBufLen < sizeof(ULONG) * NUM_COM_ULONGS) { Status = STATUS_BUFFER_TOO_SMALL; *outBufLen = sizeof(ULONG) * NUM_COM_ULONGS; } else { #ifdef USE_COM_STATUS_LIST if (CprGetComStatus(Irp, TRUE)) { status = STATUS_PENDING; release = FALSE; } #else KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); if (HasComStatusChanged()) { CopyComStatus((ULONG*)Irp->AssociatedIrp.SystemBuffer); KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); Irp->IoStatus.Information = sizeof(ULONG) * NUM_COM_ULONGS; } else { // Save IRP and return Pending // Needs to be on a per session basis. // PCPR_SESSION pSession; KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, FALSE); if (!pSession) pSession = CreateSession(TRUE); if (pSession) { if (pSession->ComStatusIrp) { // Another Process is listening // The next version of CPR needs to create a list // of these based on the processId. Status = STATUS_DEVICE_ALREADY_ATTACHED; Irp->IoStatus.Information = 0; } else { IoMarkIrpPending(Irp); pSession->ComStatusIrp = Irp; Status = STATUS_PENDING; release = FALSE; } } } #endif } break; case CPR_IOCTL_CANCEL_COM_STATUS_WAIT: // Cancel the CPR_IOCTL_GET_COM_STATUS_WAIT IRP. // { PCPR_SESSION pSession; pSession = CprFindSession(&gSessionQueue, GetSessionId(), FALSE, TRUE); if (pSession) { KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); if (pSession->ComStatusIrp) { pSession->ComStatusIrp->IoStatus.Information = 0; pSession->ComStatusIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pSession->ComStatusIrp, IO_NO_INCREMENT); pSession->ComStatusIrp = NULL; } KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); if (pSession->EventLogActive == FALSE) { __try { // Find and DeQueue pSession = CprFindSession(&gSessionQueue, GetSessionId(), TRUE, TRUE); if (pSession) CprCleanUpSession(pSession); } __except( EXCEPTION_EXECUTE_HANDLER ) { } } } } break; default: Status = STATUS_INVALID_PARAMETER; break; } } if (release) { Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } CprDebugPrint2(NULL, DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p release %d", Irp, release); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = STATUS_INTERNAL_ERROR; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); CprDebugPrint1(NULL, DBG_IO, DBG_TRACE, __FUNCTION__"-EXCEPTION!. IRP %p", Irp); } return Status; } PCPR_SESSION CreateSession( BOOLEAN lock ) { PCPR_SESSION pSession = (PCPR_SESSION)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_SESSION), CPR_POOL_TAG_SESSION ); if (pSession) { RtlFillMemory(pSession, sizeof(CPR_SESSION), '\0'); pSession->SessionId = GetSessionId(); CprInitializeEventLogQueue(&pSession->EventLogQueue); CprQueueSession(&gSessionQueue, pSession, lock); } return pSession; } #ifdef USE_COM_STATUS_LIST BOOLEAN CprGetComStatus( PIRP Irp, BOOLEAN wait ) { KIRQL oldIrql; // Grab Queue Lock KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); // Check if there is data if we need to wait if ((wait == FALSE) || HasComStatusChanged()) { // Do not need to release all the other CopyComStatus((ULONG*)Irp->AssociatedIrp.SystemBuffer); KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); Irp->IoStatus.Information = sizeof(ULONG) * NUM_COM_ULONGS; } else { // Here because wait is TRUE and there are no status changes } } #endif // gSessionQueue.QueueLock is locked before this call void CopyComStatus(ULONG *statusArg) { int n; for (n = 0; n < NUM_COM_ULONGS; n++) { statusArg[n] = g_Data.ComStatus[n]; g_Data.ComStatus[n] = 0; //Clear } } void ComStatusClear( int portNumber ) { int portMinusOne = portNumber - 1; unsigned int comNdx = portMinusOne >> 5; unsigned int comMask = (1 << (portMinusOne % 32)); // Set bit to zero g_Data.ComStatus[comNdx] &= ~comMask; } void ComStatusChange( PCPR_DEVICE_EXTENSION pDevExt, USHORT comStatus ) { unsigned int comNdx; unsigned int comMask; PLIST_ENTRY entry; PCPR_SESSION pSession; KIRQL oldIrql; if (comStatus != pDevExt->ComStatus) { int portMinusOne = pDevExt->portNumber - 1; KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); pDevExt->ComStatus = comStatus; comNdx = portMinusOne >> 5; comMask = (1 << (portMinusOne % 32)); g_Data.ComStatus[comNdx] |= comMask; // Now check for any waiting IRPs, check each session. // Loop through each registered session. for (entry = gSessionQueue.ListHead.Flink; entry != &gSessionQueue.ListHead; entry = entry->Flink) { // Get the Session from the entry pSession = CONTAINING_RECORD(entry, CPR_SESSION, ListEntry); if (pSession && (pSession->ComStatusIrp != NULL)) { CopyComStatus((ULONG*)pSession->ComStatusIrp->AssociatedIrp.SystemBuffer); pSession->ComStatusIrp->IoStatus.Information = sizeof(ULONG) * NUM_COM_ULONGS; pSession->ComStatusIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pSession->ComStatusIrp, IO_NO_INCREMENT); pSession->ComStatusIrp = NULL; } } KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); } } void NetworkStatusChange( PCPR_DEVICE_EXTENSION pDevExt, USHORT netStatus ) { unsigned int comNdx; unsigned int comMask; PLIST_ENTRY entry; PCPR_SESSION pSession; KIRQL oldIrql; if (netStatus != pDevExt->NetworkStatus) { int portMinusOne = pDevExt->portNumber - 1; KeAcquireSpinLock(&gSessionQueue.QueueLock, &oldIrql); pDevExt->NetworkStatus = netStatus; comNdx = portMinusOne >> 5; comMask = (1 << (portMinusOne % 32)); g_Data.ComStatus[comNdx] |= comMask; // Now check for any waiting IRPs, check each session. // Loop through each registered session. for (entry = gSessionQueue.ListHead.Flink; entry != &gSessionQueue.ListHead; entry = entry->Flink) { // Get the Session from the entry pSession = CONTAINING_RECORD(entry, CPR_SESSION, ListEntry); if (pSession && (pSession->ComStatusIrp != NULL)) { CopyComStatus((ULONG*)pSession->ComStatusIrp->AssociatedIrp.SystemBuffer); pSession->ComStatusIrp->IoStatus.Information = sizeof(ULONG) * NUM_COM_ULONGS; pSession->ComStatusIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pSession->ComStatusIrp, IO_NO_INCREMENT); pSession->ComStatusIrp = NULL; } } KeReleaseSpinLock(&gSessionQueue.QueueLock, oldIrql); } } BOOLEAN HasComStatusChanged() { int n; for (n = 0; n < NUM_COM_ULONGS; n++) { if (g_Data.ComStatus[n] != 0) return TRUE; } return FALSE; } /* * BackdoorEventLogRead * * Transfers data from the the kernel to * the calling app's read buffer. * */ NTSTATUS BackdoorEventLogRead (PIRP Irp) { KIRQL OldIrql; NTSTATUS Status = STATUS_INTERNAL_ERROR; PBACKDOOR_DEVICE_EXTENSION bdExt; ULONG sessionId; PCPR_SESSION pSession; sessionId = GetSessionId(); pSession = CprFindSession(&gSessionQueue, sessionId, FALSE, FALSE); if (!pSession) { pSession = CreateSession(TRUE); if (pSession) pSession->EventLogActive = TRUE; } KeAcquireSpinLock(&gSessionQueue.QueueLock, &OldIrql); if (pSession) { /* Mark the Irp pending (assuming there's no data for it)*/ IoSetCancelRoutine (Irp, BackdoorEventLogCancelRoutine); if (Irp->Cancel) { // // If the IRP was cancelled after we put in our cancel routine we // will get back NULL here and we will let the cancel routine handle // the IRP. If NULL is not returned here then we know the IRP was // cancelled before we inserted the queue cancel routine, and we // need to call our cancel routine to handle the IRP. // if (IoSetCancelRoutine(Irp, NULL) != NULL) { // cancel the IRP Status = STATUS_CANCELLED; Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; KeReleaseSpinLock(&gSessionQueue.QueueLock, OldIrql); return Status; } } IoMarkIrpPending (Irp); Irp->IoStatus.Status = STATUS_PENDING; Status = STATUS_PENDING; CprDebugPrint1(NULL, DBG_IO, DBG_INFO, " Read Irp for SessionId %d", sessionId); pSession->EventLogIrp = Irp; Status = GiveEventLogDataToApp(pSession); } KeReleaseSpinLock(&gSessionQueue.QueueLock, OldIrql); return Status; } void BackdoorEventLogCancelRoutine (PDEVICE_OBJECT DeviceObject, PIRP Irp) { PBACKDOOR_DEVICE_EXTENSION ext = DeviceObject->DeviceExtension; unsigned char i; // KdPrint((" BackdoorEventLogCancelRoutine Called\n")); // Hmmmm... do we use the array or go through the linked list off // the DeviceObject? Using the array assumes that it's up-to-date, // meaning that I have to handle all the insert/delete device stuff // correctly... // for (i = 0; i < ext->numPorts; i++) { //PCPR_DEVICE_EXTENSION // serialExt = (PCPR_DEVICE_EXTENSION)ext->serialDevice[i]-> // DeviceExtension; // } IoReleaseCancelSpinLock (Irp->CancelIrql); if (IoSetCancelRoutine (Irp, NULL)) { Irp->IoStatus.Status = STATUS_CANCELLED; //DumpICRI("SimpleCancelRoutine.1", Irp); IoCompleteRequest (Irp, IO_NO_INCREMENT); } } /* * GiveEventLogDataToApp * * Make sure this function is called at DPC level? * * Copies data from the kernel to the * app's read Irp system buffer, wakes up the app's * read thread. * */ NTSTATUS GiveEventLogDataToApp(PCPR_SESSION pSession) { ULONG copyLength = 0; NTSTATUS Status = STATUS_PENDING; ULONG i; PUCHAR ptr; //PBACKDOOR_DEVICE_EXTENSION bdExt; PIRP readIrp; readIrp = pSession->EventLogIrp; if (readIrp && (readIrp->Cancel == FALSE)) { // // We have an Irp // PCPR_EVENT_LOG pEvtLogFromApp = (PCPR_EVENT_LOG)readIrp->AssociatedIrp.SystemBuffer; if (pEvtLogFromApp) { PCPR_EVENT_LOG_KERNEL pEvtLogFromQue = CprDeQueueEventLog(&pSession->EventLogQueue); if (pEvtLogFromQue) { CprDebugPrint2(NULL, DBG_PNP, DBG_INFO, __FUNCTION__": Copying From %p to %p", pEvtLogFromQue, pEvtLogFromApp); *pEvtLogFromApp = pEvtLogFromQue->eventLog; pSession->EventLogIrp = NULL; // // Release backdoor pending read // if (IoSetCancelRoutine (readIrp, NULL)) { readIrp->IoStatus.Information = sizeof(CPR_EVENT_LOG); readIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest (readIrp, IO_NO_INCREMENT); //bdExt->BackdoorEventLogPendingRead = NULL; } Status = STATUS_PENDING; // We released it, or previous cancel did, so tell calling routine not to. CprReleaseEventLog(pEvtLogFromQue); } } } return Status; } /* * BackdoorCleanup * * Cleanup routine for backdoor device. For now all it does * is cancel any pending Irps * */ void BackdoorCleanup (PDEVICE_OBJECT DeviceObject, PIRP Irp) { if (g_Data.BackdoorDevice != NULL) { PBACKDOOR_DEVICE_EXTENSION bdExt; //PIRP readIrp; //PCPR_EVENT_LOG pEventLog; bdExt = (PBACKDOOR_DEVICE_EXTENSION)g_Data.BackdoorDevice->DeviceExtension; CprCleanUpSessions(); } } void BackdoorCancelIrp (PDEVICE_OBJECT DeviceObject, PIRP *ppIrp) { PDRIVER_CANCEL cancelRoutine; if (*ppIrp) { cancelRoutine = (*ppIrp)->CancelRoutine; (*ppIrp)->Cancel = TRUE; //SerialDump( // SERDIAGJIM, // ("SIMPLE: calling cancelRoutine for %x\n", *ppIrp) // ); if (cancelRoutine) { cancelRoutine (DeviceObject, *ppIrp); } *ppIrp = NULL; } } char *IoctlToString(ULONG ioCode) { switch(ioCode) { case CPR_IOCTL_RELOAD_REGISTRY: return "CPR_IOCTL_RELOAD_REGISTRY"; break; case CPR_IOCTL_CLOSE_PORT: return "CPR_IOCTL_CLOSE_PORT"; break; case CPR_IOCTL_DISCONNECT_NETWORK: return "CPR_IOCTL_DISCONNECT_NETWORK"; break; case CPR_IOCTL_GET_PORT_INFO: return "CPR_IOCTL_GET_PORT_INFO"; break; case CPR_IOCTL_GET_PORT_STATUS: return "CPR_IOCTL_GET_PORT_STATUS"; break; case CPR_IOCTL_GET_PORT_DEVICE: return "CPR_IOCTL_GET_PORT_DEVICE"; break; case CPR_IOCTL_SET_PORT_INFO: return "CPR_IOCTL_SET_PORT_INFO"; break; case CPR_IOCTL_UPDATE_DRIVER: return "CPR_IOCTL_UPDATE_DRIVER"; break; case CPR_IOCTL_GET_VERSION: return "CPR_IOCTL_GET_VERSION"; break; case CPR_IOCTL_EVENT_READ: return "CPR_IOCTL_EVENT_READ"; break; case CPR_IOCTL_STATUS_READ: return "CPR_IOCTL_STATUS_READ"; break; case CPR_IOCTL_SET_EVENT_LOG_BUFFER: return "CPR_IOCTL_SET_EVENT_LOG_BUFFER"; break; case CPR_IOCTL_CLEAR_EVENT_LOG_BUFFER: return "CPR_IOCTL_CLEAR_EVENT_LOG_BUFFER"; break; case CPR_IOCTL_EVENT_LOG_WAIT: return "CPR_IOCTL_EVENT_LOG_WAIT"; break; case CPR_IOCTL_START_EVENT_READ: return "CPR_IOCTL_START_EVENT_READ"; break; case CPR_IOCTL_CANCEL_EVENT_READ: return "CPR_IOCTL_CANCEL_EVENT_READ"; break; case CPR_IOCTL_GET_FILTER_DATA: return "CPR_IOCTL_GET_FILTER_DATA"; break; case CPR_IOCTL_SET_FILTER_DATA: return "CPR_IOCTL_SET_FILTER_DATA"; break; case CPR_IOCTL_CLR_FILTER_DATA: return "CPR_IOCTL_CLR_FILTER_DATA"; break; case CPR_IOCTL_EVENT_SEND_DEBUG: return "CPR_IOCTL_EVENT_SEND_DEBUG"; break; case CPR_IOCTL_SET_EVENT_LOG_FILTER: return "CPR_IOCTL_SET_EVENT_LOG_FILTER"; break; case CPR_IOCTL_CLEAR_EVENT_LOG_FILTER: return "CPR_IOCTL_CLEAR_EVENT_LOG_FILTER"; break; case CPR_IOCTL_GET_EVENT_LOG_FILTER: return "CPR_IOCTL_GET_EVENT_LOG_FILTER"; break; case CPR_IOCTL_SET_EVENT_LOG_IOCTL_FILTER: return "CPR_IOCTL_SET_EVENT_LOG_IOCTL_FILTER"; break; case CPR_IOCTL_CLEAR_EVENT_LOG_IOCTL_FILTER: return "CPR_IOCTL_CLEAR_EVENT_LOG_IOCTL_FILTER"; break; case CPR_IOCTL_GET_EVENT_LOG_IOCTL_FILTER: return "CPR_IOCTL_GET_EVENT_LOG_IOCTL_FILTER"; break; case CPR_IOCTL_SET_DEBUG_LEVEL: return "CPR_IOCTL_SET_DEBUG_LEVEL"; break; case CPR_IOCTL_GET_DEBUG_LEVEL: return "CPR_IOCTL_GET_DEBUG_LEVEL"; break; case CPR_IOCTL_SET_EVENT_FLAGS: return "CPR_IOCTL_SET_EVENT_FLAGS"; break; case CPR_IOCTL_GET_EVENT_FLAGS: return "CPR_IOCTL_GET_EVENT_FLAGS"; break; case CPR_IOCTL_SET_DEBUG_AREA: return "CPR_IOCTL_SET_DEBUG_AREA"; break; case CPR_IOCTL_GET_DEBUG_AREA: return "CPR_IOCTL_GET_DEBUG_AREA"; break; case CPR_IOCTL_FLUSH_EVENT_LOG_QUEUE: return "CPR_IOCTL_FLUSH_EVENT_LOG_QUEUE"; break; case CPR_IOCTL_GET_PERF_COUNTER: return "CPR_IOCTL_GET_PERF_COUNTER"; break; case CPR_IOCTL_GET_PERF_FREQ: return "CPR_IOCTL_GET_PERF_FREQ"; break; case CPR_IOCTL_GET_COM_STATUS: return "CPR_IOCTL_GET_COM_STATUS"; break; case CPR_IOCTL_GET_COM_STATUS_WAIT: return "CPR_IOCTL_GET_COM_STATUS_WAIT"; break; case CPR_IOCTL_CANCEL_COM_STATUS_WAIT: return "CPR_IOCTL_CANCEL_COM_STATUS_WAIT"; break; default: return "Unknown"; break; } }