Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sample TDI kernel-mode client

419 views
Skip to first unread message

Gary Nebbett

unread,
Apr 16, 1998, 3:00:00 AM4/16/98
to

Having searched the net, I could not find even one example of a TDI kernel-mode
client,
so in case there are other people who would be interested in experimenting with
TDI, I
have attached to this message a toy driver which I have used to experiment with
TDI.

Vijay Shrivastav is currently developing a "Windows NT TDI Reference" at
http://www.rabox.com/atage/ and this promises to be a useful resource for TDI
client development.

Gary Nebbett

-------------------------
extern "C" {
#include <ntddk.h>
#include "tdikrnl.h"
}


NTSTATUS
CreateConnection(PHANDLE Handle, PFILE_OBJECT *FileObject)
{
UNICODE_STRING Name; RtlInitUnicodeString(&Name, L"\\Device\\Tcp");

OBJECT_ATTRIBUTES Attr; InitializeObjectAttributes(&Attr, &Name,
OBJ_CASE_INSENSITIVE, 0, 0);

CHAR Buffer[sizeof (FILE_FULL_EA_INFORMATION) +
TDI_CONNECTION_CONTEXT_LENGTH];

PFILE_FULL_EA_INFORMATION Ea = PFILE_FULL_EA_INFORMATION(Buffer);

Ea->NextEntryOffset = 0;
Ea->Flags = 0;
Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
Ea->EaValueLength = 0;
RtlCopyMemory(Ea->EaName, TdiConnectionContext, Ea->EaNameLength + 1);

IO_STATUS_BLOCK IoStatus;

NTSTATUS Status = ZwCreateFile(Handle, 0, &Attr, &IoStatus, 0,
FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, 0, Ea, sizeof Buffer);

if (!NT_SUCCESS(Status)) return Status;

return ObReferenceObjectByHandle(*Handle, GENERIC_READ | GENERIC_WRITE, 0,
KernelMode,
(PVOID *)FileObject, 0);
}


NTSTATUS
CreateAddress(PHANDLE Handle, PFILE_OBJECT *FileObject)
{
UNICODE_STRING Name; RtlInitUnicodeString(&Name, L"\\Device\\Tcp");

OBJECT_ATTRIBUTES Attr; InitializeObjectAttributes(&Attr, &Name,
OBJ_CASE_INSENSITIVE, 0, 0);

CHAR Buffer[sizeof (FILE_FULL_EA_INFORMATION) +
TDI_TRANSPORT_ADDRESS_LENGTH +
sizeof (TA_IP_ADDRESS)];

PFILE_FULL_EA_INFORMATION Ea = PFILE_FULL_EA_INFORMATION(Buffer);

Ea->NextEntryOffset = 0;
Ea->Flags = 0;
Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
Ea->EaValueLength = sizeof (TA_IP_ADDRESS);
RtlCopyMemory(Ea->EaName, TdiTransportAddress, Ea->EaNameLength + 1);

PTA_IP_ADDRESS Sin = PTA_IP_ADDRESS(Ea->EaName + Ea->EaNameLength + 1);
Sin->TAAddressCount = 1;
Sin->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
Sin->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
Sin->Address[0].Address[0].sin_port = 0;
Sin->Address[0].Address[0].in_addr = 0;
RtlZeroMemory(Sin->Address[0].Address[0].sin_zero, sizeof
Sin->Address[0].Address[0].sin_zero);

IO_STATUS_BLOCK IoStatus;

NTSTATUS Status = ZwCreateFile(Handle, 0, &Attr, &IoStatus, 0,
FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, 0, Ea, sizeof Buffer);

if (!NT_SUCCESS(Status)) return Status;

return ObReferenceObjectByHandle(*Handle, GENERIC_READ | GENERIC_WRITE, 0,
KernelMode,
(PVOID *)FileObject, 0);
}


NTSTATUS
SetEventHandler(PFILE_OBJECT FileObject, LONG EventType, PVOID EventHandler,
PVOID EventContext)
{
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

IO_STATUS_BLOCK IoStatus;

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER,
DeviceObject, FileObject,
&Event, &IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

TdiBuildSetEventHandler(Irp, DeviceObject, FileObject, 0, 0,
EventType, EventHandler, EventContext);

NTSTATUS Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);

return Status == STATUS_SUCCESS ? IoStatus.Status : Status;
}


NTSTATUS
Bind(PFILE_OBJECT FileObject, HANDLE Address)
{
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

IO_STATUS_BLOCK IoStatus;

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS,
DeviceObject, FileObject,
&Event, &IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

TdiBuildAssociateAddress(Irp, DeviceObject, FileObject, 0, 0, Address);

NTSTATUS Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);

return Status == STATUS_SUCCESS ? IoStatus.Status : Status;
}


NTSTATUS
Connect(PFILE_OBJECT FileObject, ULONG Addr, USHORT Port)
{
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

IO_STATUS_BLOCK IoStatus;

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT, DeviceObject,
FileObject,
&Event, &IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

TA_IP_ADDRESS DstAddr = {1, {TDI_ADDRESS_LENGTH_IP, TDI_ADDRESS_TYPE_IP,
{Port, Addr}}};

TDI_CONNECTION_INFORMATION Dst = {0, 0, 0, 0, sizeof DstAddr, &DstAddr};

TdiBuildConnect(Irp, DeviceObject, FileObject, 0, 0, 0, &Dst, 0);

NTSTATUS Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);

return Status == STATUS_SUCCESS ? IoStatus.Status : Status;
}


NTSTATUS
Disconnect(PFILE_OBJECT FileObject)
{
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

IO_STATUS_BLOCK IoStatus;

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, DeviceObject,
FileObject,
&Event, &IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

TdiBuildDisconnect(Irp, DeviceObject, FileObject, 0, 0, 0,
TDI_DISCONNECT_RELEASE, 0, 0);

NTSTATUS Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);

return Status == STATUS_SUCCESS ? IoStatus.Status : Status;
}


NTSTATUS
Send(PFILE_OBJECT FileObject, PVOID Data, ULONG Length)
{
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

IO_STATUS_BLOCK IoStatus;

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND, DeviceObject,
FileObject,
&Event, &IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

PMDL Mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, Irp);

if (Mdl == 0) return STATUS_INSUFFICIENT_RESOURCES;

MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);

TdiBuildSend(Irp, DeviceObject, FileObject, 0, 0, Mdl, 0, Length);

NTSTATUS Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);

return Status == STATUS_SUCCESS ? IoStatus.Status : Status;
}


NTSTATUS
Recv(PFILE_OBJECT FileObject, PVOID Data, ULONG Length, PKEVENT Event,
PIO_STATUS_BLOCK IoStatus)
{
PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);

PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE, DeviceObject,
FileObject,
Event, IoStatus);

if (Irp == 0) return STATUS_INSUFFICIENT_RESOURCES;

PMDL Mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, Irp);

MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);

TdiBuildReceive(Irp, DeviceObject, FileObject, 0, 0, Mdl,
TDI_RECEIVE_NORMAL, Length);

return IoCallDriver(DeviceObject, Irp);
}


NTSTATUS
EventDisconnect(PVOID EventContext, CONNECTION_CONTEXT, LONG, PVOID, LONG,
PVOID, ULONG Flags)
{
DbgPrint("Flags = %lx\n", Flags);

KeSetEvent(PKEVENT(EventContext), 0, FALSE);

return STATUS_SUCCESS;
}


NTSTATUS
EventError(PVOID, NTSTATUS Status)
{
DbgPrint("Error = %lx\n", Status);

return STATUS_SUCCESS;
}


NTSTATUS
EventReceive(PVOID, CONNECTION_CONTEXT, ULONG Flags, ULONG Indicated, ULONG
Available,
PULONG Taken, PVOID, PIRP *Irp)
{
DbgPrint("Receive Flags = %lx, Ind = %ld, Avl = %ld\n", Flags, Indicated,
Available);

*Taken = Available; *Irp = 0;

return STATUS_SUCCESS;
}


NTSTATUS
Test()
{
PFILE_OBJECT ConnectionFileObject, AddressFileObject;
HANDLE AddressHandle, ConnectionHandle;
CHAR Buffer[80], Data[] = "Hello from Gary";
NTSTATUS Status;

KEVENT Done; KeInitializeEvent(&Done, NotificationEvent, FALSE);

Status = CreateConnection(&ConnectionHandle, &ConnectionFileObject);
if (!NT_SUCCESS(Status)) return Status;

Status = CreateAddress(&AddressHandle, &AddressFileObject);
if (!NT_SUCCESS(Status)) return Status;

do {
Status = SetEventHandler(AddressFileObject, TDI_EVENT_DISCONNECT,
EventDisconnect, &Done);
if (!NT_SUCCESS(Status)) break;

Status = SetEventHandler(AddressFileObject, TDI_EVENT_ERROR, EventError, 0);
if (!NT_SUCCESS(Status)) break;

Status = SetEventHandler(AddressFileObject, TDI_EVENT_RECEIVE, EventReceive,
0);
if (!NT_SUCCESS(Status)) break;

Status = Bind(ConnectionFileObject, AddressHandle);
if (!NT_SUCCESS(Status)) break;

Status = Connect(ConnectionFileObject, 0x41A1F6A8, 0x700);
if (!NT_SUCCESS(Status)) break;

IO_STATUS_BLOCK IoStatus;
KEVENT Event; KeInitializeEvent(&Event, NotificationEvent, FALSE);

Status = Recv(ConnectionFileObject, Buffer, sizeof Buffer, &Event, &IoStatus);
if (!NT_SUCCESS(Status)) break;

Status = Send(ConnectionFileObject, Data, sizeof Data);
if (!NT_SUCCESS(Status)) break;

Status = Send(ConnectionFileObject, Data, sizeof Data);
if (!NT_SUCCESS(Status)) break;

Status = Send(ConnectionFileObject, Data, sizeof Data);
if (!NT_SUCCESS(Status)) break;

Status = Disconnect(ConnectionFileObject);
if (!NT_SUCCESS(Status)) break;

Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0);
if (Status == STATUS_SUCCESS) Status = IoStatus.Status;

DbgPrint("Status = %lx, IoStatus.Status = %lx, IoStatus.Information = %ld\n",
Status, IoStatus.Status, IoStatus.Information);

KeWaitForSingleObject(&Done, UserRequest, KernelMode, FALSE, 0);

} while (0);

ObDereferenceObject(ConnectionFileObject);

ObDereferenceObject(AddressFileObject);

ZwClose(ConnectionHandle);

ZwClose(AddressHandle);

return Status;
}


NTSTATUS
DriverOpenClose(PDEVICE_OBJECT, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return STATUS_SUCCESS;
}


VOID
DriverUnload(PDRIVER_OBJECT DriverObject)
{
IoDeleteDevice(DriverObject->DeviceObject);
}


extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
NTSTATUS Status = Test();

if (!NT_SUCCESS(Status)) return Status;

DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverOpenClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverOpenClose;
DriverObject->DriverUnload = DriverUnload;

UNICODE_STRING Name; RtlInitUnicodeString(&Name, L"\\Device\\TdiTest");

PDEVICE_OBJECT DeviceObject;

return IoCreateDevice(DriverObject, 0, &Name, FILE_DEVICE_UNKNOWN, 0, TRUE,
&DeviceObject);
}


Message has been deleted
Message has been deleted
0 new messages