Good day. I'm trying to write a kernel mode code that uses the TDI interface to accept incoming TCP-connections. And this I can not. Schematic code shown below. Attempt to connect via telnet for the first time succeeds — Irp->IoStatus.Status == STATUS_SUCCESS, but when I try to send / receive data through that connection, I get STATUS_INVALID_DEVICE_STATE (0xC0000184). At this time Process Explorer shows listening socket and the established connection on the same port. Subsequent attempts to connect get Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A). I can not understand why. Maybe I do not understand the mechanism? I would be grateful for the help.
/* Listen-socket has two lists — the list of sockets that are waiting to connect — backlog, as I understand it,
** and the list of sockets that are already connected. Access to lists regulates the Queued-SpinLock —
** in order to operate on the list was possible on IRQL <= DISPATCH_LEVEL.
** KernelSocketAccept(__in PKERNEL_SOCKET Socket, __out PKERNEL_SOCKET * AcceptedConnectionSocket) interface function
** waits for SocketConnectedEvent and when connected socket(sockets) appears in the ConnectedSockets list, takes connected
** socket from this list and returns pointer on it in output parameter.
*/
//File connection to the device to be a transport driver
struct _TransportDeviceFile{
HANDLE Handle;
PFILE_OBJECT Object;
} TransportDeviceFile;
//File of the local address associated with a socket
struct _LocalAddressFile{
HANDLE Handle;
PFILE_OBJECT Object;
} LocalAddressFile;
//List of sockets that are waiting to connect, and a list of sockets for which the connection is established
KERNEL_SOCKET_LIST WaitingSockets;
KERNEL_SOCKET_LIST ConnectedSockets;
//Event, stating that the incoming connection is accepted and connected socket is placed on the list ConnectedSockets
KEVENT SocketConnectedEvent;
} KERNEL_SOCKET, *PKERNEL_SOCKET;
//Context structure is transmitted with TDI_ACCEPT IRP
typedef struct _TDI_ACCEPT_IRP_CONTEXT{
//Pointer to Listen-socket
PKERNEL_SOCKET ListeningSocket;
//Pointer to a socket that accepts connection
PKERNEL_SOCKET AcceptSocket;
//If pointer TDIAcceptIRPContext is correct
if(TDIAcceptIRPContext){
//If pointers ListeningSocket and AcceptSocket are correct
if(TDIAcceptIRPContext->ListeningSocket && TDIAcceptIRPContext->AcceptSocket){
//If the connection is successfully established
if(Irp->IoStatus.Status == STATUS_SUCCESS){
//Set the appropriate flag in the socket
TDIAcceptIRPContext->AcceptSocket->Connected = true;
//Add a socket to the list of connected sockets of the listening socket
AppendSocketToSocketList(&TDIAcceptIRPContext->ListeningSocket->ConnectedSockets, TDIAcceptIRPContext->AcceptSocket);
//Set the event, stating that the incoming connection is accepted and connected socket is placed in the list ConnectedSockets
KeSetEvent(&TDIAcceptIRPContext->ListeningSocket->SocketConnectedEvent, IO_NO_INCREMENT, FALSE);
}
}
//ClientEventConnect
static NTSTATUS TDIClientEventIncomingConnection(IN PVOID TdiEventContext,
IN LONG RemoteAddressLength,
IN PVOID RemoteAddress,
IN LONG UserDataLength,
IN PVOID UserData,
IN LONG OptionsLength,
IN PVOID Options,
OUT CONNECTION_CONTEXT * ConnectionContext,
OUT PIRP * AcceptIrp){
//TdiEventContext — is a pointer to KERNEL_SOCKET, for which it was installed this Callback procedure
PKERNEL_SOCKET Socket = (PKERNEL_SOCKET)TdiEventContext;
//If it succeeded
if(AcceptConnectionIRP){
//Allocate context structure in the non-paged pool
PTDI_ACCEPT_IRP_CONTEXT TDIAcceptIRPContext = (PTDI_ACCEPT_IRP_CONTEXT)ExAllocateFromNPagedLookasideList(&KernelSocketsModule.DataBufferLookAsideList);
//If it succeeded
if(TDIAcceptIRPContext){
//Initialize the contextual structure
local_memset(TDIAcceptIRPContext, 0x00, sizeof(TDI_ACCEPT_IRP_CONTEXT));
//Retrieve the socket from the socket, waiting for connection
PKERNEL_SOCKET SocketFromTheWaitingList = TakeSocketFromSocketList(&Socket->WaitingSockets);
//If it succeeded
if(SocketFromTheWaitingList){
//Put pointers to listening socket and a socket that accepts a connection
TDIAcceptIRPContext->ListeningSocket = Socket;
TDIAcceptIRPContext->AcceptSocket = SocketFromTheWaitingList;
//Module interface function
NTSTATUS KernelSocketListen(__in PKERNEL_SOCKET Socket){
/* Creation of a number of sockets for use in ClientEventConnect — backlog.
** Creation consists of opening the connection to the transport driver — ZwCreateFile()
** and subsequent TDI_ASSOCIATE_ADDRESS.
** Puts these sockets in the list, access to which regulates the Queued-SpinLock —
** in order to operate on the list was possible on IRQL <= DISPATCH_LEVEL.
** This list is tied to the current listening socket — for which this function is called.
** All these actions are fully successful.
*/
/* Then form the IRP — TDI_SET_EVENT_HANDLER with EventType == TDI_EVENT_CONNECT and
** call IoCallDriver(). As PFILE_OBJECT FileObj gives the address file object of this listen socket.
** Returns STATUS_SUCCESS.
*/
/* It seems that in this function everything is working properly */