// tdicall.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "tdicall.tmh" #endif #if 0 void DataSent(PCPR_TDI_SOCKET Socket, PCPR_DEVICE_EXTENSION pDevExt) { NTSTATUS status; TDI_PROVIDER_STATISTICS provStats; PMDL provMdl; provMdl = IoAllocateMdl((PVOID)&provStats, sizeof(TDI_PROVIDER_STATISTICS), FALSE, FALSE, NULL); if(provMdl) { MmBuildMdlForNonPagedPool(provMdl); status = CprTdiQueryInformation(Socket, TDI_QUERY_PROVIDER_STATISTICS, provMdl); CprDebugPrint5(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". <><><><><><><><><> status %X\n DataGramBytes %d\n" " DataFrameBytes %d\n DfbResent %d\n DfbRejected %d\n", status, provStats.DatagramBytesSent.LowPart, provStats.DataFrameBytesSent.LowPart, provStats.DataFrameBytesResent.LowPart, provStats.DataFrameBytesRejected.LowPart); } } #endif /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAllocateIrpPool // allocates pool of irps used in socket operations // // Arguments: // IN Socket // our socket // // IN IrpCount // number of IRPs to preallocate // // // Return Value: // NT status code // NTSTATUS CprTdiAllocateIrpPool( IN PCPR_TDI_SOCKET Socket, IN ULONG IrpCount ) { PIRP irp; NTSTATUS status; ULONG i; PDEVICE_OBJECT deviceObject; CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); InitializeListHead(&Socket->IrpList); KeInitializeSpinLock(&Socket->IrpLock); deviceObject = IoGetRelatedDeviceObject(Socket->ControlFileObject); status = STATUS_SUCCESS; for (i = 0; i < IrpCount; ++i) { irp = IoAllocateIrp(deviceObject->StackSize+1, FALSE); if (irp != NULL) { CprTdiFreeIrp(Socket, irp); } else { status = STATUS_INSUFFICIENT_RESOURCES; break; } } if (!NT_SUCCESS(status)) { CprTdiFreeIrpPool(Socket); } CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiFreeIrpPool // frees all the preallocated irps // // Arguments: // IN Socket // our socket // // Return Value: // None // VOID CprTdiFreeIrpPool( IN PCPR_TDI_SOCKET Socket ) { PIRP irp; CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); while (irp = CprTdiAllocIrp(Socket)) { IoFreeIrp(irp); } CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAllocIrp // allocates an IRP from socket irp pool // // Arguments: // IN Socket // our socket // // Return Value: // Irp // PIRP CprTdiAllocIrp( IN PCPR_TDI_SOCKET Socket ) { PLIST_ENTRY listEntry; PIRP irp; CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); listEntry = ExInterlockedRemoveHeadList(&Socket->IrpList, &Socket->IrpLock); if (listEntry != NULL) { irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry); } else { irp = NULL; } CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--. IRP %p", irp); return irp; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiFreeIrp // frees an IRP back to socket IRP pool // // Arguments: // IN Socket // our socket // // IN Irp // irp to free // // // Return Value: // None // VOID CprTdiFreeIrp( IN PCPR_TDI_SOCKET Socket, IN PIRP Irp ) { CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); if (Socket && Irp && Irp->Type == IO_TYPE_IRP) { IoReuseIrp(Irp, STATUS_SUCCESS); if ((Socket->IrpList.Flink != NULL) && (Socket->IrpList.Blink != NULL)) { ExInterlockedInsertHeadList( &Socket->IrpList, &Irp->Tail.Overlay.ListEntry, &Socket->IrpLock ); } else { CprDebugPrint2(NULL, DBG_TDI, DBG_ERR, __FUNCTION__" Error: NULL Socket ListEntry: SockF %p, SockB %p", Socket->IrpList.Flink, Socket->IrpList.Blink); } } else { CprDebugPrint2(NULL, DBG_TDI, DBG_ERR, __FUNCTION__" Error Socket %p Irp %p", Socket, Irp); } CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAllocateConnectSocketPool // preallocates connect sockets // // Arguments: // IN Socket // listen type socket // // IN SocketCount // number of sockets to preallocate // // // Return Value: // Status // NTSTATUS CprTdiAllocateConnectSocketPool( IN PCPR_TDI_SOCKET Socket, IN ULONG SocketCount ) { PCPR_TDI_SOCKET connectSocket; ULONG i; NTSTATUS status; PDEVICE_OBJECT deviceObject; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); InitializeListHead(&Socket->ConnectSocketList); KeInitializeSpinLock(&Socket->ConnectSocketLock); status = STATUS_SUCCESS; for (i = 0; i < SocketCount; ++i) { connectSocket = (PCPR_TDI_SOCKET)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_TDI_SOCKET), CPR_POOL_TAG_CON_SOCKET ); if (connectSocket != NULL) { RtlZeroMemory(connectSocket, sizeof(CPR_TDI_SOCKET)); InitializeListHead(&connectSocket->ListEntry); connectSocket->ListenSocket = Socket; connectSocket->Uart = Socket->Uart; connectSocket->ProtocolName = Socket->ProtocolName; InitializeListHead(&connectSocket->ConnectSocketList); KeInitializeSpinLock(&connectSocket->ConnectSocketLock); KeInitializeEvent(&connectSocket->WaitWriteEvent, NotificationEvent, TRUE); KeInitializeEvent(&connectSocket->Event, NotificationEvent, TRUE); KeInitializeEvent(&connectSocket->RemoveEvent, SynchronizationEvent, FALSE); connectSocket->RefCount = 1; connectSocket->ControlFileObject = Socket->ControlFileObject; ObReferenceObject(connectSocket->ControlFileObject); connectSocket->AddressFileObject = Socket->AddressFileObject; ObReferenceObject(connectSocket->AddressFileObject); status = CprTdiAllocateIrpPool(connectSocket, 8); if (NT_SUCCESS(status)) { status = CprTdiOpenConnection(connectSocket); if (NT_SUCCESS(status)) { connectSocket->AddressHandle = Socket->AddressHandle; status = CprTdiAssociateAddress(connectSocket); connectSocket->AddressHandle = NULL; } } CprTdiFreeConnectSocket(connectSocket); } else { status = STATUS_INSUFFICIENT_RESOURCES; } if (!NT_SUCCESS(status)) { break; } } if (!NT_SUCCESS(status)) { CprTdiFreeConnectSocketPool(Socket); } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiFreeConnectSocketPool // frees all preallocated connect sockets // // Arguments: // IN Socket // listen type socket // // Return Value: // None // VOID CprTdiFreeConnectSocketPool( IN PCPR_TDI_SOCKET Socket ) { PCPR_TDI_SOCKET connectSocket; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); while (connectSocket = CprTdiAllocConnectSocket(Socket)) { if (connectSocket->AddressFileObject) { CprTdiSetEventHandler(connectSocket, TDI_EVENT_CONNECT, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_DISCONNECT, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_RECEIVE, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_CHAINED_RECEIVE, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_RECEIVE_EXPEDITED, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_RECEIVE_DATAGRAM, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_CHAINED_RECEIVE_DATAGRAM, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_SEND_POSSIBLE, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_ERROR, NULL, NULL); CprTdiSetEventHandler(connectSocket, TDI_EVENT_ERROR_EX, NULL, NULL); } CprTdiDisassociateAddress(connectSocket); CprTdiCloseSocket(connectSocket); CprTdiFreeIrpPool(connectSocket); ExFreePool(connectSocket); } CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAllocConnectSocket // allocates a connect socket from preallocated socket pool // // Arguments: // IN Socket // listen type socket // // Return Value: // connect socket // PCPR_TDI_SOCKET CprTdiAllocConnectSocket( IN PCPR_TDI_SOCKET Socket ) { PLIST_ENTRY listEntry; PCPR_TDI_SOCKET connectSocket; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); listEntry = ExInterlockedRemoveHeadList(&Socket->ConnectSocketList, &Socket->ConnectSocketLock); if (listEntry != NULL) { CprTdiAddRef(Socket); connectSocket = CONTAINING_RECORD(listEntry, CPR_TDI_SOCKET, ListEntry); } else { connectSocket = NULL; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. SOCKET %p", connectSocket); return connectSocket; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiFreeConnectSocket // frees connect socket back to the pool // // Arguments: // IN Socket // connect type socket // // Return Value: // None // VOID CprTdiFreeConnectSocket( IN PCPR_TDI_SOCKET ConnectSocket ) { PCPR_TDI_SOCKET socket = NULL; CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++. ConnectSocket %p", ConnectSocket); if (ConnectSocket != NULL) { socket = ConnectSocket->ListenSocket; if (socket != NULL) { ExInterlockedInsertHeadList( &socket->ConnectSocketList, &ConnectSocket->ListEntry, &socket->ConnectSocketLock ); CprTdiRelease(socket); } } CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"-- Socket %p", socket); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAddRef // adds reference to socket // // Arguments: // IN Socket // socket // // Return Value: // None // VOID CprTdiAddRef( IN PCPR_TDI_SOCKET Socket ) { if (Socket != NULL) { InterlockedIncrement(&Socket->RefCount); } return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiRelease // releases reference // // Arguments: // IN Socket // socket // // Return Value: // None // VOID CprTdiRelease( IN PCPR_TDI_SOCKET Socket ) { if (Socket && (InterlockedDecrement(&Socket->RefCount) == 0)) { KeSetEvent(&Socket->RemoveEvent, IO_NO_INCREMENT, FALSE); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiReleaseAndWait // releases reference and waits for last reference count to be released // // Arguments: // IN Socket // socket // // Return Value: // None // VOID CprTdiReleaseAndWait( IN PCPR_TDI_SOCKET Socket ) { if (Socket) { CprTdiRelease(Socket); KeWaitForSingleObject( &Socket->RemoveEvent, Executive, KernelMode, FALSE, NULL ); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiCreateSocket // creates a socket // // Arguments: // IN ProtocolName // transport device name // // Return Value: // socket // PCPR_TDI_SOCKET CprTdiCreateSocket( IN PWSTR ProtocolName ) { PCPR_TDI_SOCKET socket; NTSTATUS status; PDEVICE_OBJECT deviceObject; CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); socket = (PCPR_TDI_SOCKET)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_TDI_SOCKET), CPR_POOL_TAG_SOCKET ); if (socket != NULL) { RtlZeroMemory(socket, sizeof(CPR_TDI_SOCKET)); InitializeListHead(&socket->ListEntry); RtlInitUnicodeString(&socket->ProtocolName, ProtocolName); KeInitializeEvent(&socket->Event, NotificationEvent, TRUE); KeInitializeEvent(&socket->WaitWriteEvent, NotificationEvent, TRUE); KeInitializeEvent(&socket->LtxLockEvent, NotificationEvent, TRUE); KeInitializeEvent(&socket->RemoveEvent, SynchronizationEvent, FALSE); socket->RefCount = 1; InitializeListHead(&socket->ConnectSocketList); KeInitializeSpinLock(&socket->ConnectSocketLock); status = IoGetDeviceObjectPointer( &socket->ProtocolName, FILE_ALL_ACCESS, &socket->ControlFileObject, &deviceObject ); if (NT_SUCCESS(status)) { status = CprTdiAllocateIrpPool(socket, 8); if (!NT_SUCCESS(status)) { ExFreePool(socket); socket = NULL; } } else { ExFreePool(socket); socket = NULL; } } CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--. SOCKET %p", socket); return socket; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiCloseSocket // closes socket // // Arguments: // IN Socket // our socket // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprTdiCloseSocket( IN PCPR_TDI_SOCKET Socket ) { PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; if (Socket->ConnectionHandle != NULL) { CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__". ConnectionHandle %p", Socket->ConnectionHandle); ZwClose(Socket->ConnectionHandle); Socket->ConnectionHandle = NULL; } if (Socket->ConnectionFileObject != NULL) { CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__". ConnectionFileObject %p", Socket->ConnectionFileObject); ObDereferenceObject(Socket->ConnectionFileObject); Socket->ConnectionFileObject = NULL; } if (Socket->AddressHandle != NULL) { CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__". AddressHandle %p", Socket->AddressHandle); ZwClose(Socket->AddressHandle); Socket->AddressHandle = NULL; } if (Socket->AddressFileObject != NULL) { CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__". ConnectionHandle %p", Socket->AddressFileObject); ObDereferenceObject(Socket->AddressFileObject); Socket->AddressFileObject = NULL; } if (Socket->ControlFileObject != NULL) { CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__". ControlFileObject %p", Socket->ControlFileObject); ObDereferenceObject(Socket->ControlFileObject); Socket->ControlFileObject = NULL; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"-- SOCKET %p", Socket); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiDeleteSocket // deletes socket // // Arguments: // IN Socket // our socket // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprTdiDeleteSocket( IN PCPR_TDI_SOCKET Socket ) { PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket) { if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++. SOCKET %p", Socket); if (Socket->AddressFileObject) { CprTdiSetEventHandler(Socket, TDI_EVENT_CONNECT, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_DISCONNECT, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_RECEIVE, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_CHAINED_RECEIVE, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_RECEIVE_EXPEDITED, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_RECEIVE_DATAGRAM, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_CHAINED_RECEIVE_DATAGRAM, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_SEND_POSSIBLE, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_ERROR, NULL, NULL); CprTdiSetEventHandler(Socket, TDI_EVENT_ERROR_EX, NULL, NULL); } CprTdiFreeConnectSocketPool(Socket); CprTdiCloseSocket(Socket); CprTdiReleaseAndWait(Socket); CprTdiFreeIrpPool(Socket); ExFreePool(Socket); } else { CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++. SOCKET NULL"); } CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiOpen // opens file object // // Arguments: // IN ProtocolName // transport device object name // // IN EaLength // Length of Ea structure // // IN Ea // extended attributes // // OUT Handle // on success holds open handle to transport address file object // // OUT FileObject // on success holds reference to transport address file object // // // Return Value: // Status // NTSTATUS CprTdiOpen( IN PUNICODE_STRING ProtocolName, IN ULONG EaLength, IN PFILE_FULL_EA_INFORMATION Ea, OUT PHANDLE Handle, OUT PFILE_OBJECT* FileObject ) { NTSTATUS status; OBJECT_ATTRIBUTES oa; IO_STATUS_BLOCK ioStatus; __try { CprDebugPrint(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); CprDebugPrint5(NULL, DBG_TDI, DBG_INFO, "ProtocolName %p EaLength %d Ea %p Handle %p FileObject %p", ProtocolName, EaLength, Ea, Handle, FileObject); CprDebugPrint2(NULL, DBG_TDI, DBG_INFO, "&oa %p &ioStatus %p", &oa, &ioStatus); // initialize ZwCreateFile parameters InitializeObjectAttributes( &oa, ProtocolName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); // open transport device object status = ZwCreateFile( Handle, GENERIC_READ | GENERIC_WRITE, &oa, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, Ea, EaLength ); if (NT_SUCCESS(status)) { status = ObReferenceObjectByHandle( *Handle, GENERIC_READ | GENERIC_WRITE, NULL, KernelMode, (PVOID*)FileObject, NULL ); if (!NT_SUCCESS(status)) { ZwClose(*Handle); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { status = STATUS_INTERNAL_ERROR; } CprDebugPrint1(NULL, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiOpenAddress // opens tdi transport address // // Arguments: // IN Socket // our socket // // IN TransportAddress // transport address // // Return Value: // Status // NTSTATUS CprTdiOpenAddress( IN PCPR_TDI_SOCKET Socket, IN PTRANSPORT_ADDRESS TransportAddress ) { ULONG eaLength; PFILE_FULL_EA_INFORMATION ea; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); eaLength = sizeof(FILE_FULL_EA_INFORMATION) + sizeof(TdiTransportAddress) + sizeof(TRANSPORT_ADDRESS) + TransportAddress->Address[0].AddressLength; ea = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, eaLength, CPR_POOL_TAG_EA); if (ea != NULL) { RtlZeroMemory(ea, eaLength); // we want to open Tdi Transport Address Object ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; RtlCopyMemory(ea->EaName, TdiTransportAddress, sizeof(TdiTransportAddress)); // copy value part of ea ea->EaValueLength = sizeof(TRANSPORT_ADDRESS) + TransportAddress->Address[0].AddressLength - 1; RtlCopyMemory(ea->EaName + sizeof(TdiTransportAddress), TransportAddress, ea->EaValueLength); // open address object status = CprTdiOpen( &Socket->ProtocolName, eaLength, ea, &Socket->AddressHandle, &Socket->AddressFileObject ); ExFreePool(ea); } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint3(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x AddressHandle %p AddressFileObject %p", status, Socket->AddressHandle, Socket->AddressFileObject); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiOpenConnection // opens tdi connection object // // Arguments: // IN Socket // our socket // // Return Value: // Status // NTSTATUS CprTdiOpenConnection( IN PCPR_TDI_SOCKET Socket ) { ULONG eaLength; PFILE_FULL_EA_INFORMATION ea; NTSTATUS status; PVOID* context; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); eaLength = sizeof(FILE_FULL_EA_INFORMATION) + sizeof(TdiConnectionContext) + sizeof(PVOID) + 1; ea = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, eaLength, CPR_POOL_TAG_EA); if (ea != NULL) { RtlZeroMemory(ea, eaLength); // we want to open Connection Object ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH; RtlCopyMemory(ea->EaName, TdiConnectionContext, sizeof(TdiConnectionContext)); // set connection context context = (PVOID*)(ea->EaName + sizeof(TdiConnectionContext)); *context = Socket; ea->EaValueLength = sizeof(PVOID); // open connection object status = CprTdiOpen( &Socket->ProtocolName, eaLength, ea, &Socket->ConnectionHandle, &Socket->ConnectionFileObject ); ExFreePool(ea); } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiRequestComplete // generic tdi request completion routine // // Arguments: // IN DeviceObject // transport device object // // IN Irp // our irp // // IN Context // our socket // // Return Value: // Status // NTSTATUS CprTdiRequestComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PCPR_TDI_SOCKET socket; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; socket = (PCPR_TDI_SOCKET)Context; if (socket->Uart) pDevExt = socket->Uart->DeviceExtension; status = Irp->IoStatus.Status; //DbgPrint(__FUNCTION__"++. STATUS %x", status); CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++. STATUS %x", status); if (Irp->UserIosb) { *Irp->UserIosb = Irp->IoStatus; } if (Irp->UserEvent) { KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); } if (Irp->MdlAddress) { IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; } CprTdiFreeIrp(socket, Irp); CprTdiRelease(socket); CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return STATUS_MORE_PROCESSING_REQUIRED; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiDirectComplete // tdi direct request completion routine // // Arguments: // IN DeviceObject // transport device object // // IN Irp // our irp // // IN Context // our socket // // Return Value: // Status // NTSTATUS CprTdiDirectComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PCPR_TDI_SOCKET socket; NTSTATUS status; PCPR_UART Uart; KIRQL oldIrql; ULONG nBytes; socket = (PCPR_TDI_SOCKET)Context; Uart = socket->Uart; nBytes = (ULONG)Irp->IoStatus.Information; socket->DirectTdiIrp = NULL; CprAcquireSerialSpinLock(Uart->DeviceExtension, &oldIrql); status = Irp->IoStatus.Status; CprDebugPrint4(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++. TDIIRP %p CURIRP %p STATUS %08X nBytes %d", Irp, Uart->DeviceExtension->WriteQueue.CurrentIrp, status, nBytes); if (Irp->UserIosb) { *Irp->UserIosb = Irp->IoStatus; } if (Irp->UserEvent) { KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); } if (Irp->MdlAddress) { IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; } CprTdiFreeIrp(socket, Irp); CprTdiRelease(socket); CprDebugPrint5(Uart->DeviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, __FUNCTION__ " TxBuffer %p, TxReadPtr %p, TxWritePtr %p, TxSendBegPtr %p, TxSendEndPtr %p", Uart->TxBuffer, Uart->TxReadPtr, Uart->TxWritePtr, Uart->TxSendBegPtr, Uart->TxSendEndPtr); CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint(Uart->DeviceExtension, DBG_TDI, DBG_TRACE, __FUNCTION__"--"); return STATUS_MORE_PROCESSING_REQUIRED; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiNoWaitRequestComplete // generic tdi request completion routine // // Arguments: // IN DeviceObject // transport device object // // IN Irp // our irp // // IN Context // our socket // // Return Value: // Status // //NTSTATUS CprTdiNoWaitRequestComplete( // IN PDEVICE_OBJECT DeviceObject, // IN PIRP Irp, // IN PVOID Context // ) //{ // PCPR_TDI_SOCKET socket; // NTSTATUS status; // PCPR_UART Uart; // PCPR_DEVICE_EXTENSION pDevExt; // // socket = (PCPR_TDI_SOCKET)Context; // Uart = socket->Uart; // pDevExt = Uart->DeviceExtension; // // status = Irp->IoStatus.Status; // // CprDebugPrint2(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++. STATUS %x BYTECOUNT %d", // status, Irp->MdlAddress->ByteCount); // // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(Uart->DeviceExtension); // // // TDI must process sequentially, or this will not work!!! // Uart->TxReadPtr += Irp->MdlAddress->ByteCount; // // ASSERT(Uart->TxReadPtr <= Uart->TxEndBuffer); // // if (Uart->TxReadPtr == Uart->TxEndBuffer) // { // Uart->TxReadPtr = Uart->TxBuffer; // if (Uart->TxWritePtr == Uart->TxEndBuffer) // Uart->TxWritePtr = Uart->TxBuffer; // } // // CprReleaseSerialSpinLockFromDpcLevel(Uart->DeviceExtension); // // IoFreeMdl(Irp->MdlAddress); // Irp->MdlAddress = NULL; // CprTdiFreeIrp(socket, Irp); // CprTdiRelease(socket); // // CprDebugPrint2(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. UART %X READPTR %X", Uart, Uart->TxReadPtr); // // return STATUS_MORE_PROCESSING_REQUIRED; //} //#define TDIIRP_TRACE /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiWriteComplete // TDI write completion routine // // Arguments: // IN DeviceObject // transport device object //` // IN Irp // our irp // // IN Context // our socket // // Return Value: // Status // NTSTATUS CprTdiWriteComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PCPR_TDI_SOCKET socket; NTSTATUS status; PCPR_UART Uart; PIRP curIrp; PIO_STACK_LOCATION irpStack; KIRQL oldIrql; ULONG nBytes; ULONG nActBytes; BOOLEAN queueSerialWriteComplete = TRUE; socket = (PCPR_TDI_SOCKET)Context; Uart = socket->Uart; status = Irp->IoStatus.Status; nBytes = (ULONG)Irp->IoStatus.Information; #ifdef TDIIRP_TRACE DbgPrint(__FUNCTION__"++. TDIIRP %p CURIRP %p SOCKIRP %p\n", Irp, Uart->DeviceExtension->WriteQueue.CurrentIrp, socket->WriteTdiIrp); DbgPrint("STATUS %08X nBytes %d Cancel %d\n", status, nBytes, Irp->Cancel); #endif CprDebugPrint4(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++. TDIIRP %p CURIRP %p STATUS %08X nBytes %d", Irp, Uart->DeviceExtension->WriteQueue.CurrentIrp, status, nBytes); // Added after the fact on 6/20/06 //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); CprAcquireSerialSpinLock(Uart->DeviceExtension, &oldIrql); socket->WriteTdiIrp = NULL; curIrp = Uart->DeviceExtension->WriteQueue.CurrentIrp; CprDebugPrint2(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". Acquired SpinLock %p curIrp %p", &Uart->DeviceExtension->SerialLock, curIrp); //if (curIrp) //{ // //Remove reference to tdi irp; // TDI_IRP_REFERENCE(curIrp) = NULL; //} CprDebugPrint2(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". STATUS %x curIrp %p", status, curIrp); if (Irp->UserIosb) { *Irp->UserIosb = Irp->IoStatus; } if ((Uart->DeviceExtension->BufferWrites) && (Uart->DeviceExtension->WriteQueue.CurrentIrp == NULL) && (status == STATUS_SUCCESS)) { //CprDumpBufPtrs(Uart->DeviceExtension, __FUNCTION__" Before"); nActBytes = nBytes - Uart->TxRFC2217Additional; Uart->TxRFC2217Additional = 0; Uart->TxTdiWriteLength -= nActBytes; if ((LONG)Uart->TxTdiWriteLength < 0) Uart->TxTdiWriteLength = 0; Uart->TxReadPtr += nActBytes; Uart->TxSendBegPtr += nActBytes; //ASSERT(Uart->TxTdiWriteLength == 0); // Check wrap around cases if (Uart->TxReadPtr >= Uart->TxEndBuffer) Uart->TxReadPtr = Uart->TxBuffer; if (Uart->TxWritePtr >= Uart->TxEndBuffer) Uart->TxWritePtr = Uart->TxBuffer; if (Uart->TxSendBegPtr >= Uart->TxEndBuffer) Uart->TxSendBegPtr = Uart->TxBuffer; if (Uart->TxSendEndPtr >= Uart->TxEndBuffer) Uart->TxSendEndPtr = Uart->TxBuffer; //CprDumpBufPtrs(Uart->DeviceExtension, __FUNCTION__" After"); } else if (status != STATUS_CANCELLED) { if ((Uart->DeviceExtension->BufferWrites) && (Uart->DeviceExtension->WriteQueue.CurrentIrp == NULL)) { // Data was not transmited, tell transmission // engine to resend Uart->TxSendEndPtr = Uart->TxSendBegPtr; } if ((int)(Uart->DeviceExtension->WriteLength - nBytes) >= 0) { Uart->DeviceExtension->WriteBuffer += nBytes; Uart->DeviceExtension->WriteLength -= nBytes; } else { //ASSERT(FALSE); Uart->DeviceExtension->WriteBuffer += Uart->DeviceExtension->WriteLength; Uart->DeviceExtension->WriteLength = 0; } if (Uart->DeviceExtension->WriteLength == 0) Uart->DeviceExtension->SystemWriteInProgress = FALSE; } if (Irp->MdlAddress) { //DbgPrint(__FUNCTION__". MDL Size %d WriteLength %d\n", // MmGetMdlByteCount(Irp->MdlAddress), Uart->DeviceExtension->WriteLength); CprDebugPrint2(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". MDL Size %d WriteLength %d", MmGetMdlByteCount(Irp->MdlAddress), Uart->DeviceExtension->WriteLength); if (Uart->DeviceExtension->UseRFC2217) { // Get Buffer and free it, it was allocated // to make room for escaping all 0xFFs PVOID buf = (PVOID)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); //CprDumpBuffer(__FUNCTION__, buf, MmGetMdlByteCount(Irp->MdlAddress)); if (buf != NULL) ExFreePool(buf); } IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; } if (Irp->UserEvent) { KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); } CprTdiFreeIrp(socket, Irp); CprTdiRelease(socket); if (status == STATUS_SUCCESS) { queueSerialWriteComplete = !TxOkToSend(Uart); //(Uart->TxReadPtr == Uart->TxWritePtr); Uart->TxEmptyEvent = TRUE; Uart->DeviceExtension->TxWriteInProgress = FALSE; Uart->DeviceExtension->TxIdle = FALSE; CprUartCheckEvents(Uart); } else if (status == STATUS_IO_TIMEOUT) { CprLogEvent( CPR_EVENT_TYPE_WRITE_TIMEOUT, CPR_EVENT_SUB_TYPE_NONE, Uart->DeviceExtension, status, NULL); if (curIrp) { // Retry!!! // curIrp->IoStatus.Status = STATUS_SUCCESS; CprUartStartWrite(Uart); // Added after the fact on 6/20/06 CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"$$ Timeout: STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } else { //Uart->TxEmptyEvent = TRUE; Uart->DeviceExtension->WriteBuffer += Uart->DeviceExtension->WriteLength; Uart->DeviceExtension->WriteLength = 0; Uart->DeviceExtension->SystemWriteInProgress = FALSE; Uart->DeviceExtension->TxWriteInProgress = FALSE; Uart->DeviceExtension->TxIdle = FALSE; CprUartCheckEvents(Uart); } } else if ((status == STATUS_INVALID_DEVICE_STATE) || (status == STATUS_CONNECTION_RESET)) { Uart->DeviceExtension->TxStopReason |= CPR_SERIAL_TX_DCD | CPR_SERIAL_TX_CTS | CPR_SERIAL_TX_DSR; if (curIrp) curIrp->IoStatus.Status = status; if ((Uart->DeviceExtension->AutoReconErr == 1) && (Uart->DeviceExtension->ListenMode == LISTEN_MODE_NONE) && (Uart->DeviceExtension->IsDeviceEnabled || Uart->DeviceExtension->NoDiscon)) { // Attempt Reconnect CprTdiStartReconnect(Uart->DeviceExtension); // Added after the fact on 6/20/06 CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"$$ InvalidDeviceState: STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } else { //Uart->TxEmptyEvent = TRUE; Uart->DeviceExtension->WriteBuffer += Uart->DeviceExtension->WriteLength; Uart->DeviceExtension->WriteLength = 0; Uart->DeviceExtension->SystemWriteInProgress = FALSE; Uart->DeviceExtension->TxWriteInProgress = FALSE; Uart->DeviceExtension->TxIdle = FALSE; CprUartCheckEvents(Uart); } } else { // This is designed for the Timer timing out and cancelling // the write. The resources are released in the timer timeout // routine. For the other cancellation reasons, // where do they get released? // could be a STATUS_CONNECTION_RESET error // if ((Uart->DeviceExtension->BufferWrites) && (Uart->DeviceExtension->WriteQueue.CurrentIrp == NULL)) { Uart->TxReadPtr += Uart->TxTdiWriteLength; Uart->TxSendBegPtr += Uart->TxTdiWriteLength; Uart->TxTdiWriteLength = 0; if (Uart->TxReadPtr >= Uart->TxEndBuffer) Uart->TxReadPtr = Uart->TxBuffer; if (Uart->TxSendBegPtr >= Uart->TxEndBuffer) Uart->TxSendBegPtr = Uart->TxBuffer; } Uart->TxEmptyEvent = TRUE; Uart->DeviceExtension->TxWriteInProgress = FALSE; Uart->DeviceExtension->TxIdle = FALSE; CprUartCheckEvents(Uart); if (curIrp) { curIrp->IoStatus.Status = status; } } // check if we are done with write irp if ((Uart->DeviceExtension->BufferWrites) && (Uart->DeviceExtension->WriteQueue.CurrentIrp == NULL)) { if (queueSerialWriteComplete) { if (Uart->DeviceExtension->TxWriteInProgress == FALSE) KeInsertQueueDpc(&Uart->DeviceExtension->WriteCompleteDpc, NULL, NULL); } } else { if ((status != STATUS_SUCCESS) || (Uart->DeviceExtension->WriteLength == 0)) { Uart->DeviceExtension->SystemWriteInProgress = FALSE; if (curIrp && (curIrp->IoStatus.Status != STATUS_CANCELLED)) { irpStack = IoGetCurrentIrpStackLocation(curIrp); if (irpStack) { curIrp->IoStatus.Information = (irpStack->MajorFunction == IRP_MJ_WRITE) ? irpStack->Parameters.Write.Length : 1; } } if (Uart->DeviceExtension->TxWriteInProgress == FALSE) KeInsertQueueDpc(&Uart->DeviceExtension->WriteCompleteDpc, NULL, NULL); } } CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". Releasing SpinLock %p", &Uart->DeviceExtension->SerialLock); CprDebugPrint5(Uart->DeviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, __FUNCTION__ " TxBuffer %p, TxReadPtr %p, TxWritePtr %p, TxSendBegPtr %p, TxSendEndPtr %p", Uart->TxBuffer, Uart->TxReadPtr, Uart->TxWritePtr, Uart->TxSendBegPtr, Uart->TxSendEndPtr); // Added after the fact on 6/20/06 CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"-- STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiWriteImmediateComplete // TDI write Immediate completion routine // // Arguments: // IN DeviceObject // transport device object // // IN Irp // our irp // // IN Context // our socket // // Return Value: // Status // NTSTATUS CprTdiWriteImmediateComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PCPR_TDI_SOCKET socket; NTSTATUS status; PCPR_UART Uart; PIRP curIrp; PIO_STACK_LOCATION irpStack; KIRQL oldIrql; socket = (PCPR_TDI_SOCKET)Context; Uart = socket->Uart; status = Irp->IoStatus.Status; CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %x", Irp); // Added after the fact on 6/20/06 //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(Uart->DeviceExtension); CprAcquireSerialSpinLock(Uart->DeviceExtension, &oldIrql); curIrp = Uart->DeviceExtension->ImmediateCharIrp; //if (curIrp) //{ // //Remove reference to tdi irp; // TDI_IRP_REFERENCE(curIrp) = NULL; //} socket->ImmediateTdiIrp = NULL; CprDebugPrint2(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__". STATUS %x curIrp %p", status, curIrp); if (Irp->UserIosb) { *Irp->UserIosb = Irp->IoStatus; } if (Irp->MdlAddress) { if (socket->Uart->DeviceExtension->UseRFC2217) { // Get Buffer and free it, it was allocated // to make room for escaping all 0xFFs PVOID buf = (PVOID)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (buf != NULL) ExFreePool(buf); } IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; } CprTdiFreeIrp(socket, Irp); CprTdiRelease(socket); if (status == STATUS_SUCCESS) { Uart->TxEmptyEvent = TRUE; CprUartCheckEvents(Uart); } else if (status == STATUS_IO_TIMEOUT) { CprLogEvent( CPR_EVENT_TYPE_WRITE_TIMEOUT, CPR_EVENT_SUB_TYPE_NONE, Uart->DeviceExtension, status, NULL); if (curIrp) { // Retry!!! // How do I restart an immediate char????? // curIrp->IoStatus.Status = STATUS_SUCCESS; CprUartStartWrite(Uart); // CprReleaseSerialSpinLockFromDpcLevel(Uart->DeviceExtension); CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"$$ Timeout: STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } else { Uart->TxEmptyEvent = TRUE; CprUartCheckEvents(Uart); Uart->DeviceExtension->TxIdle = FALSE; } } else if (status == STATUS_INVALID_DEVICE_STATE) { if ((Uart->DeviceExtension->AutoReconErr == 1) && (curIrp) && (Uart->DeviceExtension->ListenMode == LISTEN_MODE_NONE) && (Uart->DeviceExtension->IsDeviceEnabled || Uart->DeviceExtension->NoDiscon)) { // Attempt Reconnect curIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; CprTdiStartReconnect(Uart->DeviceExtension); // CprReleaseSerialSpinLockFromDpcLevel(Uart->DeviceExtension); CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"$$ InvalidDeviceState: STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } else { if ((Uart->DeviceExtension->BufferWrites) && (Uart->DeviceExtension->WriteQueue.CurrentIrp == NULL)) { Uart->TxReadPtr = Uart->TxSendEndPtr; } else { Uart->DeviceExtension->WriteLength = 0; } Uart->DeviceExtension->TxIdle = FALSE; Uart->TxEmptyEvent = TRUE; CprUartCheckEvents(Uart); } } else { // This is designed for the Timer timing out and cancelling // the write. The resources are released in the timer timeout // routine. For the other cancellation reasons, // where do they get released? // Uart->TxEmptyEvent = TRUE; CprUartCheckEvents(Uart); Uart->DeviceExtension->TxIdle = FALSE; if (curIrp) { curIrp->IoStatus.Status = status; } } Uart->DeviceExtension->TxIdle = FALSE; KeInsertQueueDpc(&Uart->DeviceExtension->ImmediateCharCompleteDpc, NULL, NULL); // Added after the fact on 6/20/06 // CprReleaseSerialSpinLockFromDpcLevel(Uart->DeviceExtension); CprReleaseSerialSpinLock(Uart->DeviceExtension, oldIrql); CprDebugPrint1(Uart->DeviceExtension, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"-- STATUS 0x%08x", status); return STATUS_MORE_PROCESSING_REQUIRED; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAssociateAddress // binds connection object with address object // // Arguments: // IN Socket // our socket // // Return Value: // Status // NTSTATUS CprTdiAssociateAddress( IN PCPR_TDI_SOCKET Socket ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildAssociateAddress( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, Socket->AddressHandle ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint3(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x ConnectionFileObject %p AddressHandle %p", status, Socket->ConnectionFileObject, Socket->AddressHandle); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiDisassociateAddress // unbinds connection object with address object // // Arguments: // IN Socket // our socket // // Return Value: // Status // NTSTATUS CprTdiDisassociateAddress( IN PCPR_TDI_SOCKET Socket ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildDisassociateAddress( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiConnect // requests a connection to remote address // // Arguments: // IN Socket // our socket // // IN RequestAddr // connection information // // OUT ReturnAddr // connection information // // Return Value: // Status // NTSTATUS CprTdiConnect( IN PCPR_TDI_SOCKET Socket, IN PTDI_CONNECTION_INFORMATION RequestAddr, OUT PTDI_CONNECTION_INFORMATION ReturnAddr ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status = STATUS_INTERNAL_ERROR; LARGE_INTEGER timeout; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket) { if (Socket->Uart == NULL) return status; pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++ Socket %p", Socket); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); // CnTmo is declared in seconds // need to convert to milliseconds // Then 100 nanoseconds timeout.QuadPart = pDevExt->CnTmo * 1000 * 10000; timeout = RtlLargeIntegerNegate(timeout); TdiBuildConnect( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, &timeout, RequestAddr, ReturnAddr ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } CprLogEvent( CPR_EVENT_TYPE_CONNECT, CPR_EVENT_SUB_TYPE_NONE, pDevExt, status, NULL); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } else { CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++ Socket %p", Socket); } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } // helper context structure used to pass information from // CprTdiReconnect to CprTdiWorkerReconnect typedef struct _CPR_RECONNECT_CONTEXT { PCPR_DEVICE_EXTENSION DeviceExtension; PIO_WORKITEM WorkItem; } CPR_RECONNECT_CONTEXT, *PCPR_RECONNECT_CONTEXT; //typedef struct _CPR_RECONNECT_CONTEXT //{ // PCPR_TDI_SOCKET Socket; // PIO_WORKITEM WorkItem; //} CPR_RECONNECT_CONTEXT, *PCPR_RECONNECT_CONTEXT; /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiWorkerReconnect // reconnect request worker routine // // Arguments: // IN DeviceObject // device object pointer // // IN Context // disconnect context // // Return Value: // None // // Comments: Runs at PASSIVE LEVEL // VOID CprTdiWorkerReconnect( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context ) { NTSTATUS status = STATUS_INTERNAL_ERROR; PCPR_RECONNECT_CONTEXT reconnectContext; PCPR_DEVICE_EXTENSION pDevExt = NULL; PCPR_UART Uart; LARGE_INTEGER totalTime; reconnectContext = (PCPR_RECONNECT_CONTEXT)Context; if (reconnectContext->DeviceExtension) { pDevExt = reconnectContext->DeviceExtension; if ((pDevExt->IsDeviceEnabled == FALSE) && (pDevExt->NoDiscon == FALSE)) { CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_INFO, "Device is disabled and not in NoNetClose Mode."); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } else if (pDevExt->NetworkStatus == CPR_NETWORK_STATUS_RECONNECTING) { Uart = &pDevExt->Uart; pDevExt->ReconnectAttempts++; //DbgPrint(__FUNCTION__"++ Reconnect Attempt %d", pDevExt->ReconnectAttempts); CprDebugPrint1(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++ Reconnect Attempt %d", pDevExt->ReconnectAttempts); // send disconnect request // DAG - We are not a server, I think this is used // if we are a server. //DbgPrint( // "Reconnecting to '%ws from %d' from Local IP:%d", // pDevExt->Services[pDevExt->CurService].Address, // pDevExt->Services[pDevExt->CurService].Port, // pDevExt->ReconnectPort); CprDebugPrint3(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_INFO, "Reconnecting to '%ws from %d' from Local IP:%d", pDevExt->Services[pDevExt->CurService].Address, pDevExt->Services[pDevExt->CurService].Port, pDevExt->ReconnectPort); CprLogEvent( CPR_EVENT_TYPE_RECONNECTING, CPR_EVENT_SUB_TYPE_NONE, pDevExt, STATUS_PENDING, NULL); //DbgPrint("DAG: CprUarClose Called From CprTdiWorkerReconnect\n"); status = CprUartClose(Uart); //DbgPrint("After CprUartClose status = %x\n", status); if ((status == STATUS_SUCCESS) || (pDevExt->socket == NULL)) { //DbgPrint("Calling CprUartConnect\n"); //NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_RECONNECTING); //status = CprUartConnect(Uart, htons(pDevExt->ReconnectPort)); //DbgPrint("After CprUartConnect 1 status = %x\n", status); //if (status == STATUS_ADDRESS_ALREADY_EXISTS) //{ NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_RECONNECTING); status = CprUartConnect(Uart, 0); //DbgPrint("After CprUartConnect 2 status = %x\n", status); //} if (status == STATUS_SUCCESS) { // Reset reconnecting flag/state //NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_CONNECTED); //pDevExt->Reconnecting = FALSE; //pDevExt->Connected = TRUE; // // If performing RFC 2217, Initialize session data // and perform negotiations here // if (pDevExt->UseRFC2217) { // // Negotiations of options occur in the normal // send/receive functions after this routine returns. // // We need to send the desired com port settings // to the connect device server. // // Should I do this all here and block, or return // and do it in the background. If we are not // connected to an RFC2217 compliant device, we // need to abort the connection. We probably should // block and find out before we return. // KIRQL oldIrql; CprAcquireSerialSpinLock(pDevExt, &oldIrql); InitBuffer(&pDevExt->ToNetBuf); CprReleaseSerialSpinLock(pDevExt, oldIrql); status = CprRfc2217_Negotiate(pDevExt); CprAcquireSerialSpinLock(pDevExt, &oldIrql); if (status == STATUS_SUCCESS) { CprRfc2217_SendPortSettings(pDevExt); } else { SOCKET socket = pDevExt->socket; pDevExt->socket = NULL; // The device server on the other end is not running // RFC2217. Refuse the connection; CprDebugPrint2(pDevExt, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__". Disconnecting from '%ws:%d'", pDevExt->Services[pDevExt->CurService].Address, pDevExt->Services[pDevExt->CurService].Port); if (socket) { CprReleaseSerialSpinLock(pDevExt, oldIrql); CprTdiDisconnect(socket, FALSE, NULL, NULL); CprTdiDeleteSocket(socket); CprAcquireSerialSpinLock(pDevExt, &oldIrql); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } if (pDevExt->QueueBuffer) { ExFreePool(pDevExt->QueueBuffer); pDevExt->QueueBuffer = NULL; } //if (deviceExtension->BfWriteQueueBuffer) //{ // ExFreePool(deviceExtension->BfWriteQueueBuffer); // deviceExtension->BfWriteQueueBuffer = NULL; //} // mark device as disabled pDevExt->IsDeviceEnabled = FALSE; pDevExt->IsDeviceOpening = FALSE; //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif if (pDevExt->OpenHandleCount > 0) { InterlockedDecrement(&pDevExt->OpenHandleCount); } } CprReleaseSerialSpinLock(pDevExt, oldIrql); } #ifdef SCPR if (pDevExt->AES) { CprPortAESInit(pDevExt); } #endif CprLogEvent( CPR_EVENT_TYPE_RECONNECTED, CPR_EVENT_SUB_TYPE_NONE, pDevExt, status, NULL); // Get Queue Started again CprUartStartWrite(Uart); } } if (status != STATUS_SUCCESS) { if (((pDevExt->ReconLimit == 0) || (pDevExt->ReconnectAttempts < pDevExt->ReconLimit))) { totalTime.QuadPart = 2000 * 10000; // Don't call again for 2 seconds totalTime = RtlLargeIntegerNegate(totalTime); KeSetTimer(&pDevExt->ReconnectTimer, totalTime, &pDevExt->ReconnectTimeoutDpc); // record that device extension has reconnect timer routine pDevExt->ReconnectRef |= CPR_DEVEXT_RECONNECT; } else { CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_INFO, "Terminating Reconnect Attempts."); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } } } else { CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_INFO, "Network Status not in reconnecting mode."); NetworkStatusChange(pDevExt, CPR_NETWORK_STATUS_DISCONNECTED); } CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"-- STATUS 0x%08X", status); } else { CprDebugPrint(NULL, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++-- Error: No Device Extension!"); } IoFreeWorkItem(reconnectContext->WorkItem); ExFreePool(reconnectContext); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiReconnectTimeout // Reconnect request timeout callback // // Arguments: // IN Dpc // WriteTimeoutDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprTdiReconnectTimeout( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; PIRP irp; BOOLEAN startNext; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; deviceExtension->ReconnectRef &= ~CPR_DEVEXT_RECONNECT; CprDebugPrint(deviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++"); CprTdiReconnect(deviceExtension); CprDebugPrint(deviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiReconnect // reconnect Socket // // Arguments: // IN DeviceExtension // Device Extension // // Return Value: // Status // NTSTATUS CprTdiReconnect( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { PDEVICE_OBJECT deviceObject; PCPR_RECONNECT_CONTEXT reconnectContext; //DbgPrint(__FUNCTION__"++"); CprDebugPrint(DeviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++"); // allocate reconnect context reconnectContext = (PCPR_RECONNECT_CONTEXT)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_RECONNECT_CONTEXT), CPR_POOL_TAG_RECON_CONTEXT ); if (reconnectContext != NULL) { reconnectContext->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject); reconnectContext->DeviceExtension = DeviceExtension; if (reconnectContext->WorkItem != NULL) { // Set the reconnecting state NetworkStatusChange(DeviceExtension, CPR_NETWORK_STATUS_RECONNECTING); IoQueueWorkItem(reconnectContext->WorkItem, CprTdiWorkerReconnect, DelayedWorkQueue, reconnectContext); } else { ExFreePool(reconnectContext); } } CprDebugPrint(DeviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--"); return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiStartReconnect // start of reconnecting Socket // // Arguments: // IN DeviceExtension // Device Extension // // Return Value: // Status // NTSTATUS CprTdiStartReconnect( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; CprDebugPrint(DeviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++"); if (DeviceExtension->NetworkStatus == CPR_NETWORK_STATUS_RECONNECTING) { CprDebugPrint(DeviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$ Already attempting reconnect"); } DeviceExtension->ReconnectAttempts = 0; //DeviceExtension->Reconnecting = TRUE; //DeviceExtension->Connected = FALSE; //NetworkStatusChange(DeviceExtension, CPR_NETWORK_STATUS_RECONNECTING); status = CprTdiReconnect(DeviceExtension); CprDebugPrint(DeviceExtension, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"-- Status 0x%08X", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiDisconnect // initiates a disconnect from remote target // // Arguments: // IN Socket // our socket // // IN Abort // abort connection // // IN RequestConnectionInfo // connection information // // OUT ReturnConnectionInfo // connection information // // Return Value: // Status // NTSTATUS CprTdiDisconnect( IN PCPR_TDI_SOCKET Socket, IN BOOLEAN Abort, IN PTDI_CONNECTION_INFORMATION RequestConnectionInfo, OUT PTDI_CONNECTION_INFORMATION ReturnConnectionInfo ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status = STATUS_INTERNAL_ERROR; LARGE_INTEGER timeout; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart == NULL) return status; pDevExt = Socket->Uart->DeviceExtension; //DbgPrint(__FUNCTION__"++"); CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); if (Socket->ConnectionFileObject) { deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, __FUNCTION__"++ deviceObject %p", deviceObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; timeout.QuadPart = pDevExt->CnTmo * 1000 * 10000; timeout = RtlLargeIntegerNegate(timeout); CprTdiAddRef(Socket); CprDebugPrint1(pDevExt, DBG_TDI, DBG_INFO, "Calling TdiBuildDisconnect (Conn Obj %p)", Socket->ConnectionFileObject); TdiBuildDisconnect( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, &timeout, Abort ? TDI_DISCONNECT_ABORT : TDI_DISCONNECT_RELEASE, RequestConnectionInfo, ReturnConnectionInfo ); status = IoCallDriver(deviceObject, irp); if ((status == STATUS_PENDING) && (pDevExt->DpcThreadId != PsGetCurrentThreadId())) { CprDebugPrint(pDevExt, DBG_TDI, DBG_INFO, "Waiting in KeWaitForSingleObject"); KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } //if ((pDevExt->ListenMode == LISTEN_MODE_NONE) && // (pDevExt->AutoReconErr) && // (pDevExt->IsDeviceEnabled || pDevExt->NoDiscon)) //{ // DbgPrint("Calling CprTdiStartReconnect: Com %d Net %d", pDevExt->ComStatus, pDevExt->NetworkStatus); // CprDebugPrint(pDevExt, DBG_WRITE | DBG_IO, DBG_INFO, "Calling CprTdiStartReconnect"); // CprTdiStartReconnect(pDevExt); // status = STATUS_SUCCESS; //} CprLogEvent( CPR_EVENT_TYPE_DISCONNECT, CPR_EVENT_SUB_TYPE_NONE, pDevExt, status, NULL); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSend // sends packet to target // // Arguments: // IN Socket // our socket // // IN Flags // send flags // // IN Mdl // data to send // // IN Length // send buffer length // // Return Value: // Status // NTSTATUS CprTdiSend( IN PCPR_TDI_SOCKET Socket, IN ULONG Flags, IN PMDL Mdl, IN ULONG Length ) { PIRP tdiIrp; PDEVICE_OBJECT deviceObject; NTSTATUS status = STATUS_INTERNAL_ERROR; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (!Socket) return status; if (Socket->Uart == NULL) return status; pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++ Len %d", Length); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); //if (pDevExt->WaitOnWrite) //{ KeClearEvent(&Socket->Event); //} tdiIrp = CprTdiAllocIrp(Socket); if (tdiIrp != NULL) { PIRP userIrp = pDevExt->WriteQueue.CurrentIrp; //if (pDevExt->WaitOnWrite) // tdiIrp->UserEvent = userIrp->UserEvent; tdiIrp->UserEvent = &Socket->Event; tdiIrp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); //if (userIrp) // TDI_IRP_REFERENCE(userIrp) = tdiIrp; Socket->WriteTdiIrp = tdiIrp; #ifdef TDIIRP_TRACE DbgPrint(__FUNCTION__": TDIIRP %p CURIRP %p\n", tdiIrp, userIrp); #endif // Length may depend on the underlying transport // Do I need to do a call on the transport to // find the maximum size? // TdiBuildSend( tdiIrp, deviceObject, Socket->ConnectionFileObject, CprTdiWriteComplete, Socket, Mdl, Flags, Length ); ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); CprReleaseSerialSpinLockFromDpcLevel(pDevExt); status = IoCallDriver(deviceObject, tdiIrp); CprAcquireSerialSpinLockAtDpcLevel(pDevExt); //KdPrint(("CprTdiSend: IoCallDriver Returned 0x%08X\n", status)); if (status == STATUS_PENDING) { // Can't wait here, IRQL too high. //if (pDevExt->WaitOnWrite) //{ // KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); //} status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_ERR, __FUNCTION__" ########### CprTdiAllocIrp FAILED"); } CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCancelTdiIrps // cancel Tdi Irp // // Arguments: // IN Socket // our socket // // Return Value: // Boolean // // Comment: // This method is called with SerialLock held // BOOLEAN CprCancelTdiIrps( IN PCPR_DEVICE_EXTENSION pDevExt ) { PCPR_TDI_SOCKET Socket; BOOLEAN retResult = FALSE; BOOLEAN cancelResult; // There is an issue with calling this routine. // If we cancel a TDI IRP, then TCP/IP will // automatically close the connection // with the device server. TCP thinks // that if you are cancelling an IRP then // there must be a problem and will therefore // shut down the connection. I talked to // a Microsoft engineer and he looked at // the OS code and found out that this // behavior is by design. // -- bummer // #ifdef _DONT_DO_FOR_NOW #ifdef TDIIRP_TRACE DbgPrint(__FUNCTION__"++\n"); #endif CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); Socket = pDevExt->socket; if (Socket) { if (Socket->WriteTdiIrp) { PIRP tdiIrp = Socket->WriteTdiIrp; Socket->WriteTdiIrp = NULL; //tdiIrp->IoStatus.Information = 0; #ifdef TDIIRP_TRACE DbgPrint(__FUNCTION__" SOCKET %p, WRITETDIIRP %p\n", Socket, tdiIrp); #endif CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, __FUNCTION__" SOCKET %p, WRITETDIIRP %p", Socket, tdiIrp); CprReleaseSerialSpinLockFromDpcLevel(pDevExt); cancelResult = IoCancelIrp(tdiIrp); retResult |= cancelResult; CprAcquireSerialSpinLockAtDpcLevel(pDevExt); if (!cancelResult) { // Need to wait on an event from the completion routine // How do I see if the connection is broken if (tdiIrp->MdlAddress != NULL) { IoFreeMdl(tdiIrp->MdlAddress); tdiIrp->MdlAddress = NULL; } CprTdiFreeIrp(Socket, tdiIrp); } } } else { retResult = TRUE; } #ifdef TDIIRP_TRACE DbgPrint(__FUNCTION__"-- result %d\n", retResult); #endif CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"-- result %d", retResult); #endif return retResult; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSendImmediate // sends packet to target // // Arguments: // IN Socket // our socket // // IN Flags // send flags // // IN Mdl // data to send // // IN Length // send buffer length // // Return Value: // Status // NTSTATUS CprTdiSendImmediate( IN PCPR_TDI_SOCKET Socket, IN ULONG Flags, IN PMDL Mdl, IN ULONG Length ) { PIRP tdiIrp; PDEVICE_OBJECT deviceObject; NTSTATUS status = STATUS_INTERNAL_ERROR; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (!Socket) return status; if (Socket->Uart == NULL) return status; pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); //KeClearEvent(&Socket->Event); tdiIrp = CprTdiAllocIrp(Socket); if (tdiIrp != NULL) { PIRP userIrp = pDevExt->ImmediateCharIrp; tdiIrp->UserEvent = &Socket->Event; tdiIrp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); //if (userIrp) // TDI_IRP_REFERENCE(userIrp) = tdiIrp; Socket->ImmediateTdiIrp = tdiIrp; //KdPrint(("CprTdiSend: userIrp %p tdiIrp %p\n", userIrp, tdiIrp)); // Length may depend on the underlying transport // Do I need to do a call on the transport to // find the maximum size? // TdiBuildSend( tdiIrp, deviceObject, Socket->ConnectionFileObject, CprTdiWriteImmediateComplete, Socket, Mdl, Flags, Length ); ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); CprReleaseSerialSpinLockFromDpcLevel(pDevExt); status = IoCallDriver(deviceObject, tdiIrp); CprAcquireSerialSpinLockAtDpcLevel(pDevExt); //KdPrint(("CprTdiSend: IoCallDriver Returned 0x%08X\n", status)); if (status == STATUS_PENDING) { status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_ERR, __FUNCTION__" ########### CprTdiAllocIrp FAILED"); } CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSendDirect // sends packet to target and waits // // Arguments: // IN Socket // our socket // // IN Flags // send flags // // IN Mdl // data to send // // IN Length // send buffer length // // Return Value: // Status // NTSTATUS CprTdiSendDirect( IN PCPR_TDI_SOCKET Socket, IN ULONG Flags, IN PMDL Mdl, IN ULONG Length, BOOLEAN Wait ) { PIRP tdiIrp; PDEVICE_OBJECT deviceObject; NTSTATUS status = STATUS_INTERNAL_ERROR; PCPR_DEVICE_EXTENSION pDevExt = NULL; BOOLEAN b = FALSE; if (!Socket) return status; if (Socket->Uart == NULL) return status; pDevExt = Socket->Uart->DeviceExtension; #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"++\n"); #endif CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); tdiIrp = CprTdiAllocIrp(Socket); if (tdiIrp != NULL) { CprTdiAddRef(Socket); Socket->DirectTdiIrp = tdiIrp; #ifdef CPR_DBG_PRINT DbgPrint("CprTdiSendDirect: tdiIrp %p\n", tdiIrp); #endif CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_INFO, "CprTdiSendDirect: tdiIrp %p", tdiIrp); if ((pDevExt->Closing == FALSE) && (pDevExt->DpcThreadId != PsGetCurrentThreadId()) && Wait) { KeClearEvent(&pDevExt->Rfc2217SendEvent); tdiIrp->UserEvent = &pDevExt->Rfc2217SendEvent; tdiIrp->UserIosb = &Socket->IoStatus; } // Length may depend on the underlying transport // Do I need to do a call on the transport to // find the maximum size? // TdiBuildSend( tdiIrp, deviceObject, Socket->ConnectionFileObject, CprTdiDirectComplete, Socket, Mdl, Flags, Length ); if (KeGetCurrentIrql() == DISPATCH_LEVEL) { b = TRUE; CprReleaseSerialSpinLockFromDpcLevel(pDevExt); } status = IoCallDriver(deviceObject, tdiIrp); #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" After IoCallDriver status 0x%08X\n", status); #endif if ((pDevExt != NULL) && (pDevExt->DpcThreadId != PsGetCurrentThreadId()) && Wait) { if (status == STATUS_PENDING) { #ifndef IMTESTING KeSetTimer( &pDevExt->Rfc2217Timer, pDevExt->Rfc2217Timeout, &pDevExt->Rfc2217TimeoutDpc); KeWaitForSingleObject(&pDevExt->Rfc2217SendEvent, Executive, KernelMode, FALSE, NULL); KeCancelTimer(&pDevExt->Rfc2217Timer); #endif status = Socket->IoStatus.Status; //#ifdef CPR_DBG_PRINT // DbgPrint(__FUNCTION__" After KeWaitForSingleObject status 0x%08X\n", status); //#endif } } if (b) { CprAcquireSerialSpinLockAtDpcLevel(pDevExt); } } else { status = STATUS_INSUFFICIENT_RESOURCES; CprDebugPrint(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_ERR, __FUNCTION__" ########### CprTdiAllocIrp FAILED"); } #ifdef CPR_DBG_PRINT DbgPrint("--. STATUS %x\n", status); #endif CprDebugPrint1(pDevExt, DBG_WRITE | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiReceive // receive packet from a target // // Arguments: // IN Socket // our socket // // IN Flags // receive flags // // IN Mdl // receive buffer // // IN Length // receive buffer length // // Return Value: // Status // NTSTATUS CprTdiReceive( IN PCPR_TDI_SOCKET Socket, IN ULONG Flags, IN PMDL Mdl, IN ULONG Length ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildReceive( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, Mdl, Flags, Length ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSendDatagram // sends a datagram to a target // // Arguments: // IN Socket // our socket // // IN Mdl // send buffer // // IN Length // send buffer size // // IN SendDatagramInfo // send info // // Return Value: // Status // // Serial Lock NOT Held // NTSTATUS CprTdiSendDatagram( IN PCPR_TDI_SOCKET Socket, IN PMDL Mdl, IN ULONG Length, IN PTDI_CONNECTION_INFORMATION SendDatagramInfo, IN PLARGE_INTEGER Timeout ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (!Socket) { return STATUS_INTERNAL_ERROR; } if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->AddressFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildSendDatagram( irp, deviceObject, Socket->AddressFileObject, CprTdiRequestComplete, Socket, Mdl, Length, SendDatagramInfo ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { status = KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, Timeout); } if (status == STATUS_SUCCESS) status = Socket->IoStatus.Status; } else { IoFreeMdl(Mdl); status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiReceiveDatagram // receives a datagram from a target // // Arguments: // IN Socket // our socket // // IN Mdl // receive buffer // // IN Length // receive buffer size // // IN ReceiveDatagramInfo // receive info // // OUT ReturnInfo // returned receive info // // Return Value: // Status // NTSTATUS CprTdiReceiveDatagram( IN PCPR_TDI_SOCKET Socket, IN PMDL Mdl, IN ULONG Length, IN PTDI_CONNECTION_INFORMATION ReceiveDatagramInfo, OUT PTDI_CONNECTION_INFORMATION ReturnInfo ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (!Socket) { return STATUS_INTERNAL_ERROR; } if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->AddressFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildReceiveDatagram( irp, deviceObject, Socket->AddressFileObject, CprTdiRequestComplete, Socket, Mdl, Length, ReceiveDatagramInfo, ReturnInfo, TDI_RECEIVE_NORMAL ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_READ | DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiListen // listens for a connection request // // Arguments: // IN Socket // our socket // // IN RequestConnectionInfo // connection information // // OUT ReturnConnectionInfo // returned connection information // // Return Value: // Status // NTSTATUS CprTdiListen( IN PCPR_TDI_SOCKET Socket, IN PTDI_CONNECTION_INFORMATION RequestConnectionInfo, OUT PTDI_CONNECTION_INFORMATION ReturnConnectionInfo ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildListen( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, 0, RequestConnectionInfo, ReturnConnectionInfo ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAccept // accepts a connection request // // Arguments: // IN Socket // our socket // // IN RequestConnectionInfo // connection information // // OUT ReturnConnectionInfo // returned connection information // // Return Value: // Status // NTSTATUS CprTdiAccept( IN PCPR_TDI_SOCKET Socket, IN PTDI_CONNECTION_INFORMATION RequestConnectionInfo, OUT PTDI_CONNECTION_INFORMATION ReturnConnectionInfo ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ConnectionFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildAccept( irp, deviceObject, Socket->ConnectionFileObject, CprTdiRequestComplete, Socket, RequestConnectionInfo, ReturnConnectionInfo ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI | DBG_IO, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSetEventHandler // sets an event handler // // Arguments: // IN Socket // our socket // // IN EventType // type of event // // IN EventHandler // event handler function // // IN EventContext // context to be passed in EventHandler // // Return Value: // Status // NTSTATUS CprTdiSetEventHandler( IN PCPR_TDI_SOCKET Socket, IN LONG EventType, IN PVOID EventHandler, IN PVOID EventContext ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->AddressFileObject) { if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->AddressFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildSetEventHandler( irp, deviceObject, Socket->AddressFileObject, CprTdiRequestComplete, Socket, EventType, EventHandler, EventContext ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } } else { status = STATUS_INTERNAL_ERROR; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiQueryInformation // queries information from transport object // // Arguments: // IN Socket // our socket // // IN QueryType // type of info // // IN Mdl // result buffer // // Return Value: // Status // NTSTATUS CprTdiQueryInformation( IN PCPR_TDI_SOCKET Socket, IN ULONG QueryType, IN PMDL Mdl ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PFILE_OBJECT fileObject; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); // FIXME: if ((QueryType == TDI_QUERY_CONNECTION_INFO) || (QueryType == TDI_QUERY_PROVIDER_STATISTICS)) { fileObject = Socket->ConnectionFileObject; } else if ((QueryType == TDI_QUERY_ADDRESS_INFO) || (QueryType == TDI_QUERY_NETWORK_ADDRESS) || (QueryType == TDI_QUERY_DATA_LINK_ADDRESS)) { fileObject = Socket->AddressFileObject; } else { fileObject = Socket->ControlFileObject; } deviceObject = IoGetRelatedDeviceObject(fileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildQueryInformation( irp, deviceObject, fileObject, CprTdiRequestComplete, Socket, QueryType, Mdl ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { IoFreeMdl(Mdl); status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSetInformation // sets information to transport object // // Arguments: // IN Socket // our socket // // IN SetType // type of info // // IN Mdl // info buffer // // Return Value: // Status // NTSTATUS CprTdiSetInformation( IN PCPR_TDI_SOCKET Socket, IN ULONG SetType, IN PMDL Mdl ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PFILE_OBJECT fileObject; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); // FIXME: if (SetType == TDI_QUERY_ADDRESS_INFO) { fileObject = Socket->AddressFileObject; } else { fileObject = Socket->ControlFileObject; } deviceObject = IoGetRelatedDeviceObject(fileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildSetInformation( irp, deviceObject, fileObject, CprTdiRequestComplete, Socket, SetType, Mdl ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } //#define TCP_SOCKET_NODELAY 1 //#define TCP_SOCKET_KEEPALIVE 2 //#define TCP_SOCKET_OOBINLINE 3 //#define TCP_SOCKET_BSDURGENT 4 //#define TCP_SOCKET_ATMARK 5 //#define TCP_SOCKET_WINDOW 6 #define TCP_SOCKET_KEEPALIVE_VALS 7 typedef struct TCPKeepAlive { ULONG onOff; ULONG keepAliveTime; ULONG keepAliveInterval; } TCPKeepAlive; // helper context structure used to pass information from // CprTdiSetKeepAlive to CprTdiSetKeepAliveWorker typedef struct _CPR_KEEPALIVE_CONTEXT { PCPR_TDI_SOCKET Socket; BOOLEAN onOff; PIO_WORKITEM WorkItem; } CPR_KEEPALIVE_CONTEXT, *PCPR_KEEPALIVE_CONTEXT; NTSTATUS TdiSetKeepAlive( IN PCPR_TDI_SOCKET Socket, BOOLEAN onOff ) { TCPKeepAlive tcpKeepAlive; int bFlag; PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; PIO_STACK_LOCATION StackLocation; NTSTATUS status; VOID *pBuf; unsigned int size; PIRP irp; PTCP_REQUEST_SET_INFORMATION_EX pSetInformation; //DbgPrint("TdiSetKeepAlive"); if (Socket && Socket->Uart) { if (onOff == TRUE) { tcpKeepAlive.onOff = TRUE; tcpKeepAlive.keepAliveInterval = Socket->Uart->DeviceExtension->KeepAliveInterval; tcpKeepAlive.keepAliveTime = Socket->Uart->DeviceExtension->KeepAliveTime; pBuf = (VOID*)&tcpKeepAlive; size = sizeof(tcpKeepAlive); } else { bFlag = 0; pBuf = (VOID*)&bFlag; size = sizeof(bFlag); } fileObject = Socket->ConnectionFileObject; deviceObject = IoGetRelatedDeviceObject(fileObject); pSetInformation = (PTCP_REQUEST_SET_INFORMATION_EX) ExAllocatePoolWithTag( NonPagedPool, sizeof(TCP_REQUEST_SET_INFORMATION_EX) + size, CPR_POOL_TAG_KEEPALIVE); RtlZeroMemory ( pSetInformation, sizeof(TCP_REQUEST_SET_INFORMATION_EX) + size); // set tdi obj struct pSetInformation->ID.toi_entity.tei_entity = CO_TL_ENTITY; pSetInformation->ID.toi_entity.tei_instance = TL_INSTANCE; // =0; pSetInformation->ID.toi_class = INFO_CLASS_PROTOCOL; pSetInformation->ID.toi_type = INFO_TYPE_CONNECTION; //pSetInformation->ID.toi_id = TCP_SOCKET_KEEPALIVE; // =2 pSetInformation->ID.toi_id = TCP_SOCKET_KEEPALIVE_VALS; // =7 RtlMoveMemory(pSetInformation->Buffer, pBuf, size); pSetInformation->BufferSize = size; irp = IoBuildDeviceIoControlRequest( IOCTL_TCP_SET_INFORMATION_EX, deviceObject, (PVOID)pSetInformation, sizeof(TCP_REQUEST_SET_INFORMATION_EX) + size, NULL, 0, FALSE, &Socket->Event, &Socket->IoStatus); if (irp) { StackLocation = IoGetNextIrpStackLocation(irp); StackLocation->DeviceObject = deviceObject; // TDI device StackLocation->FileObject = fileObject; // Connect file object status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { //DbgPrint("TdiSetKeepAlive: Wait Before"); KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; //DbgPrint("TdiSetKeepAlive: Waot After"); } } } return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiSetKeepAliveWorker // TCP KeepAlive worker routine // // Arguments: // PCPR_TDI_SOCKET Socket, // pointer to Socket // // BOOLEAN onOff // Turn on or off // // Return Value: // None // // Comments: Runs at PASSIVE LEVEL // VOID CprTdiSetKeepAliveWorker( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context ) { NTSTATUS status = STATUS_SUCCESS; PCPR_KEEPALIVE_CONTEXT keepAliveContext; PCPR_DEVICE_EXTENSION pDevExt = NULL; PCPR_UART Uart; //DbgPrint("CprTdiSetKeepAliveWorker"); keepAliveContext = (PCPR_KEEPALIVE_CONTEXT)Context; TdiSetKeepAlive(keepAliveContext->Socket, keepAliveContext->onOff); IoFreeWorkItem(keepAliveContext->WorkItem); ExFreePool(keepAliveContext); } NTSTATUS CprTdiSetKeepAlive( IN PCPR_TDI_SOCKET Socket, BOOLEAN onOff ) { PDEVICE_OBJECT deviceObject; PCPR_KEEPALIVE_CONTEXT keepAliveContext; PCPR_DEVICE_EXTENSION pDevExt = NULL; //DbgPrint("CprTdiSetKeepAlive"); if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++"); if (KeGetCurrentIrql() == PASSIVE_LEVEL) { TdiSetKeepAlive(Socket, onOff); } else { // allocate reconnect context keepAliveContext = (PCPR_KEEPALIVE_CONTEXT)ExAllocatePoolWithTag( NonPagedPool, sizeof(CPR_KEEPALIVE_CONTEXT), CPR_POOL_TAG_KEEPALIVE_CONTEXT ); if (keepAliveContext != NULL) { keepAliveContext->WorkItem = IoAllocateWorkItem(pDevExt->DeviceObject); keepAliveContext->Socket = Socket; keepAliveContext->onOff = onOff; if (keepAliveContext->WorkItem != NULL) { // Set the reconnecting state IoQueueWorkItem(keepAliveContext->WorkItem, CprTdiSetKeepAliveWorker, DelayedWorkQueue, keepAliveContext); } else { ExFreePool(keepAliveContext); } } } CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--"); return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprTdiAction // requests action // // Arguments: // IN Socket // our socket // // IN Mdl // action info // // Return Value: // Status // NTSTATUS CprTdiAction( IN PCPR_TDI_SOCKET Socket, IN PMDL Mdl ) { PIRP irp; PDEVICE_OBJECT deviceObject; NTSTATUS status; PCPR_DEVICE_EXTENSION pDevExt = NULL; if (Socket->Uart) pDevExt = Socket->Uart->DeviceExtension; CprDebugPrint(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"++"); deviceObject = IoGetRelatedDeviceObject(Socket->ControlFileObject); KeClearEvent(&Socket->Event); irp = CprTdiAllocIrp(Socket); if (irp != NULL) { irp->UserEvent = &Socket->Event; irp->UserIosb = &Socket->IoStatus; CprTdiAddRef(Socket); TdiBuildAction( irp, deviceObject, Socket->ControlFileObject, CprTdiRequestComplete, Socket, Mdl ); status = IoCallDriver(deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Socket->Event, Executive, KernelMode, FALSE, NULL); status = Socket->IoStatus.Status; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } CprDebugPrint1(pDevExt, DBG_TDI, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // inet_addr // Convert IPv4 host format ULONG from a dotted string // // Arguments: // IN IpAddress // pointer to null-terminated ascii address like "1.2.3.4" // // Return Value: // 32-bit value // ULONG inet_addr( IN PCCHAR IpAddress ) { ULONG address; ULONG shift; ULONG sym; address = 0; shift = 0; while (*IpAddress) { sym = 0; while ((*IpAddress != '.') && (*IpAddress != '\0')) { // check for invalid character if ((*IpAddress < '0') || (*IpAddress > '9')) return 0; sym = sym*10 + (ULONG)(*IpAddress - '0'); ++IpAddress; } address += sym << shift; shift += 8; if (*IpAddress++ == '\0') break; } return address; } /////////////////////////////////////////////////////////////////////////////////////////////////// // inet_ntoa // Convert from ULONG to IPv4 dotted presentation // // Arguments: // IN Address // Address to convert (in network order format) // // OUT Buffer // Buffer to write output string // // IN BufferLength // Buffer size // // Return Value: // TRUE if converted. FALSE - small buffer // BOOLEAN inet_ntoa( IN ULONG Address, OUT PCHAR Buffer, IN ULONG BufferLength ) { ULONG a; ULONG i; // make sure that we can fit the longest // possible ip address if (BufferLength < 16) return FALSE; for (i = 0; i < 4; ++i) { a = (Address >> (8*i)) & 0xFF; if (a >= 100) { *Buffer++ = (CHAR)(a/100 + '0'); } if (a >= 10) { *Buffer++ = (CHAR)(a%100/10 + '0'); } *Buffer++ = (CHAR)(a%10 + '0'); if (i < 3) { *Buffer++ = '.'; } } *Buffer = 0; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////// // inet_ntow // Convert from ULONG to IPv4 dotted presentation in WCHAR format // // Arguments: // IN Address // Address to convert (in network order format) // // OUT Buffer // Wide Char Buffer to write output string // // IN BufferLength // Buffer size // // Return Value: // TRUE if converted. FALSE - small buffer // BOOLEAN inet_ntow( IN ULONG Address, OUT PWCHAR Buffer, IN ULONG BufferLength ) { ULONG a; ULONG i; // make sure that we can fit the longest // possible ip address if (BufferLength < 16) return FALSE; for (i = 0; i < 4; ++i) { a = (Address >> (8*i)) & 0xFF; if (a >= 100) { *Buffer++ = (CHAR)(a/100 + '0'); } if (a >= 10) { *Buffer++ = (CHAR)(a%100/10 + '0'); } *Buffer++ = (CHAR)(a%10 + '0'); if (i < 3) { *Buffer++ = '.'; } } *Buffer = 0; return TRUE; } // helper context structure used to pass information from // CprTdiReconnect to CprTdiWorkerReconnect //typedef struct _CPR_KEEP_ALIVE_CONTEXT //{ // PCPR_DEVICE_EXTENSION DeviceExtension; // PIO_WORKITEM WorkItem; //} CPR_KEEP_ALIVE_CONTEXT, *PCPR_KEEP_ALIVE_CONTEXT; /////////////////////////////////////////////////////////////////////////////////////////////////// // CprKeepAliveWorker // KeepAlive worker routine // // Arguments: // IN DeviceObject // device object pointer // // IN Context // disconnect context // // Return Value: // None // // Comments: Runs at PASSIVE LEVEL // //VOID CprKeepAliveWorker( // IN PDEVICE_OBJECT DeviceObject, // IN PVOID Context // ) //{ // NTSTATUS status = STATUS_SUCCESS; //STATUS_INTERNAL_ERROR; // PCPR_KEEP_ALIVE_CONTEXT keepAliveContext; // PCPR_DEVICE_EXTENSION pDevExt = NULL; // PCPR_UART Uart; // UCHAR buf[1]; // // keepAliveContext = (PCPR_KEEP_ALIVE_CONTEXT)Context; // // if (keepAliveContext->DeviceExtension) // { // pDevExt = keepAliveContext->DeviceExtension; // Uart = &pDevExt->Uart; // pDevExt->KeepAliveAttempts++; // // CprDebugPrint1(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, // __FUNCTION__"++ KeepAlive Attempt %d", pDevExt->KeepAliveAttempts); // // CprDebugPrint3(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_INFO, // "Performing Keep Alive on to '%ws from %d' from Local IP:%d", // pDevExt->Services[pDevExt->CurService].Address, // pDevExt->Services[pDevExt->CurService].Port, // pDevExt->ReconnectPort); // // status = CprUartWriteDirect(Uart, buf, 0, TRUE, TRUE); // // CprLogEvent( // CPR_EVENT_TYPE_KEEP_ALIVE, // CPR_EVENT_SUB_TYPE_NONE, // pDevExt, // status, // NULL); // // IoFreeWorkItem(keepAliveContext->WorkItem); // ExFreePool(keepAliveContext); // // CprDebugPrint(pDevExt, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"-- STATUS 0x%08X", status); // // KeSetTimer( // &pDevExt->KeepAliveTimer, // pDevExt->KeepAliveTimeout, // &pDevExt->KeepAliveTimeoutDpc); // } // else // { // CprDebugPrint(NULL, DBG_IO | DBG_TDI | DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++-- Error: No Device Extension!"); // } // // return; //} //VOID CprKeepAliveTimeout( // IN PKDPC Dpc, // IN PVOID Context, // IN PVOID Unused1, // IN PVOID Unused2 // ) //{ // PCPR_DEVICE_EXTENSION deviceExtension; // PDEVICE_OBJECT deviceObject; // PCPR_KEEP_ALIVE_CONTEXT keepAliveContext; // // // get our device extension // deviceExtension = (PCPR_DEVICE_EXTENSION)Context; // // CprDebugPrint(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++"); // // // // allocate reconnect context // keepAliveContext = (PCPR_KEEP_ALIVE_CONTEXT)ExAllocatePoolWithTag( // NonPagedPool, // sizeof(PCPR_KEEP_ALIVE_CONTEXT), // CPR_POOL_TAG_KEEPALIVE // ); // // if (keepAliveContext != NULL) // { // keepAliveContext->WorkItem = IoAllocateWorkItem(deviceExtension->DeviceObject); // keepAliveContext->DeviceExtension = deviceExtension; // // if (keepAliveContext->WorkItem != NULL) // { // // Set the reconnecting state // IoQueueWorkItem(keepAliveContext->WorkItem, CprKeepAliveWorker, DelayedWorkQueue, keepAliveContext); // } // else // { // ExFreePool(keepAliveContext); // } // } // // CprDebugPrint(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); // // return; //}