TDI Server Code

Hi,
I am attaching here my complete TDI Server code, which keeps on waiting after printing

Association Success …
Waiting on IRP (Listen)…

Please help me where I am wrong or what modifications i have to make to make it work.
If you have any sample code or useful link, please forward it.

With thanks in advance,
barun

#include <ntddk.h>
#include <tdikrnl.h>

// these are the 3 big-ones for kernel mode tcp/ip
// -----------------------------------------------
#define DD_TCP_DEVICE_NAME L"\Device\Tcp"
#define DD_UDP_DEVICE_NAME L"\Device\Udp"
#define DD_RAW_IP_DEVICE_NAME L"\Device\RawIp"

// some very useful macros
#define INETADDR(a, b, c, d) (a + (b<<8) + (c<<16) + (d<<24))
#define HTONL(a) (((a&0xFF)<<24) + ((a&0xFF00)<<8) + ((a&0xFF0000)>>8) + ((a&0xFF000000)>>24))
#define HTONS(a) (((0xFF&a)<<8) + ((0xFF00&a)>>8))

/

TDICompletionRoutine

* /

static NTSTATUS TDICompletionRoutine(IN PDEVICE_OBJECT theDeviceObject, IN PIRP theIrp, IN PVOID theContextP)
{
DbgPrint(“TDICompletionRoutine called.”);
if(NULL != theContextP)
{
DbgPrint(“calling KeSetEvent.”);
ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
KeSetEvent((PKEVENT)theContextP, 0, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}

/

OnStubDispatch

/
// we don’t use this, it’s a place holder
NTSTATUS OnStubDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp )
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest( Irp,IO_NO_INCREMENT );
return STATUS_SUCCESS;
}

/
Unload
* /
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint(“BASIC TDI: OnUnload called\n”);
}

/

DriverEntry

* /
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{

int i;
UNICODE_STRING TDI_TransportDeviceName; // For Address Handle Creation //
OBJECT_ATTRIBUTES TDI_Object_Attr;
HANDLE TDI_Address_Handle;
PVOID pAddrFileObj;

CONNECTION_CONTEXT contextPlaceholder = NULL; // For Opening Endpoint //
HANDLE TDI_Endpoint_Handle;
PVOID pConnFileObj;

NTSTATUS status;
IO_STATUS_BLOCK IoStatus;
PTA_IP_ADDRESS pSin;
ULONG ulBuffer;
PIRP pIrp;
PVOID pTcpDevObj;

KEVENT AssociateEvent;
KEVENT ConnectEvent;
KEVENT ListenEvent;
KEVENT AcceptEvent;
KEVENT RecvEvent;
TA_IP_ADDRESS RmtIPAddr;
ULONG RemoteAddr; // Remote IP address (assigned below)
USHORT RemotePort; // Remote port (assigned below)
TDI_CONNECTION_INFORMATION RmtNode;
TDI_CONNECTION_INFORMATION RcvNode;

//added for version 2
PMDL pMdl;
char RecvBfr[100];
char * pRecvBuffer;
ULONG RecvBfrLength;
ULONG EaLength;

PFILE_FULL_EA_INFORMATION pEA_Buffer;

theDriverObject->DriverUnload = OnUnload;

// install a stub for handling usermode communication
for(i=0;i< IRP_MJ_MAXIMUM_FUNCTION; i++ )
{
theDriverObject->MajorFunction[i] = OnStubDispatch;
}

// 1. Initialize object attributes
RtlInitUnicodeString( &TDI_TransportDeviceName,
DD_TCP_DEVICE_NAME // the “/device/tcp” string
);

ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

InitializeObjectAttributes(
&TDI_Object_Attr, // Attributes (to be initialized);
&TDI_TransportDeviceName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, //for win2k or higher…
0,
0
);

//2. Fill extended attributes structure
EaLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH +
sizeof(TA_IP_ADDRESS) +1;
pEA_Buffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPoolCacheAligned,EaLength);
if(!pEA_Buffer) {
DbgPrint(“ExAllocatePool … failed”);
return STATUS_INSUFFICIENT_RESOURCES;
}

pEA_Buffer->NextEntryOffset = 0; // only one entry
pEA_Buffer->Flags = 0;
pEA_Buffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
memcpy( pEA_Buffer->EaName,
TdiTransportAddress, pEA_Buffer->EaNameLength + 1);

pEA_Buffer->EaValueLength = sizeof(TA_IP_ADDRESS);

//3. Put local address here
pSin = (PTA_IP_ADDRESS) (pEA_Buffer->EaName + pEA_Buffer->EaNameLength + 1); //& ??
pSin->TAAddressCount = 1;
pSin->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
pSin->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
pSin->Address[0].Address[0].sin_port = HTONS(6000); //use some r&d
pSin->Address[0].Address[0].in_addr = INETADDR(10,6,21,63); // use 0.0.0.0
memset( pSin->Address[0].Address[0].sin_zero,
0,
sizeof(pSin->Address[0].Address[0].sin_zero)
);

//4. Open Address Object
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

status = ZwCreateFile(
&TDI_Address_Handle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&TDI_Object_Attr,
&IoStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
0,
pEA_Buffer,
EaLength
);

if(!NT_SUCCESS(status))
{
DbgPrint(“Failed to open address object, status 0x%08X”, status);
ExFreePool(pEA_Buffer);
return STATUS_UNSUCCESSFUL;
}

//5. get address object handle
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

status = ObReferenceObjectByHandle(
TDI_Address_Handle,
FILE_ANY_ACCESS,
0,
KernelMode,
(PVOID *)&pAddrFileObj,
NULL
);

/////////////////////////////////////////////////////////////////////////////
// Step 2, open a TDI endpoint
//
// This is another call to ZwCreateFile, the only thing that differs here
// is the data in the ‘magic’ EA_Buffer. Now you can see the most of the
// real arguments are passed in the EA structure! :wink:
/////////////////////////////////////////////////////////////////////////////

//1. Fill Extended Attribute Structure

EaLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_CONNECTION_CONTEXT_LENGTH +
sizeof(CONNECTION_CONTEXT) +1;
pEA_Buffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(NonPagedPool, EaLength);
if(NULL==pEA_Buffer)
{
DbgPrint(“Failed to allocate buffer”);
return STATUS_INSUFFICIENT_RESOURCES;
}

memset(pEA_Buffer, 0, EaLength);
pEA_Buffer->NextEntryOffset = 0;
pEA_Buffer->Flags = 0;
pEA_Buffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
memcpy( pEA_Buffer->EaName,
TdiConnectionContext,
pEA_Buffer->EaNameLength + 1
);

// A note on context: A CONNECTION_CONTEXT is just a pointer to a user-defined
// structure. This means you can put whatever you want in the structure.
// The reason it exists is so you can figure out WHICH connection your dealing with
// when you callbacks for received data, etc. This is obviously really important!
//
// We are only dealing with ONE connection in this example, so we set the context to
// a dummy value.
pEA_Buffer->EaValueLength = sizeof(CONNECTION_CONTEXT);
(CONNECTION_CONTEXT)(pEA_Buffer->EaName+(pEA_Buffer->EaNameLength + 1)) = (CONNECTION_CONTEXT) contextPlaceholder;

//2. Open Connection point Object
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
status = ZwCreateFile(
&TDI_Endpoint_Handle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&TDI_Object_Attr,
&IoStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
0,
pEA_Buffer,
EaLength
);

if(!NT_SUCCESS(status))
{
DbgPrint(“Failed to open endpoint, status 0x%08X”, status);
ExFreePool(pEA_Buffer);
return STATUS_UNSUCCESSFUL;
}

//3. get end point object handle
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
status = ObReferenceObjectByHandle(
TDI_Endpoint_Handle,
FILE_ANY_ACCESS,
0,
KernelMode,
(PVOID *)&pConnFileObj,
NULL
);

//////////////////////////////////////////////////////////////
// Step 3, associate the endpoint with the address
//////////////////////////////////////////////////////////////

//1. get the device associated with the address object
pTcpDevObj = IoGetRelatedDeviceObject(pAddrFileObj);

KeInitializeEvent(&AssociateEvent, NotificationEvent, FALSE);

pIrp = TdiBuildInternalDeviceControlIrp( TDI_ASSOCIATE_ADDRESS,
pTcpDevObj,
pConnFileObj,
&AssociateEvent, // Event to be signalled when Irp completes.
&IoStatus
);
if(NULL==pIrp)
{
DbgPrint(“Could not get an IRP for TDI_ASSOCIATE_ADDRESS”);
return (STATUS_INSUFFICIENT_RESOURCES);
}

// adds some more data to the IRP
TdiBuildAssociateAddress(pIrp,
pTcpDevObj,
pConnFileObj,
NULL,
NULL,
TDI_Address_Handle
);

ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IoSetCompletionRoutine( pIrp, TDICompletionRoutine, &AssociateEvent, TRUE, TRUE, TRUE);

ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
status = IoCallDriver(pTcpDevObj, pIrp);

// wait on the IRP, if required…
if (STATUS_PENDING==status)
{
DbgPrint(“Waiting on IRP (associate)…”);
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
KeWaitForSingleObject(&AssociateEvent, Executive, KernelMode, FALSE, 0);
}

if ((STATUS_SUCCESS!=status) && (STATUS_PENDING!=status))
{
DbgPrint(“IoCallDriver failed (associate), status 0x%08X”, status);
return STATUS_UNSUCCESSFUL;
}

DbgPrint(“Association Success …”);
/////////////////////////////////////////////////////////////////////////////
// Step 4. Listen
/////////////////////////////////////////////////////////////////////////////

KeInitializeEvent(&ListenEvent, NotificationEvent, FALSE);

// build an IRP to listen
pIrp = TdiBuildInternalDeviceControlIrp( TDI_LISTEN,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
&ListenEvent, // Event to be signalled when Irp completes.
&IoStatus // I/O status block.
);

if(NULL==pIrp)
{
DbgPrint(“Could not get an IRP for TDI_LISTEN”);
ExFreePool(&RmtNode);
return(STATUS_INSUFFICIENT_RESOURCES);
}

// Initialize the IP address structure
RemotePort = HTONS(6000);
RemoteAddr = INETADDR(10,6,21,20); //do some r&d

RmtIPAddr.TAAddressCount = 1;
RmtIPAddr.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
RmtIPAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
RmtIPAddr.Address[0].Address[0].sin_port = RemotePort;
RmtIPAddr.Address[0].Address[0].in_addr = RemoteAddr; // do some r&d

RmtNode.UserDataLength = 0;
RmtNode.UserData = 0;
RmtNode.OptionsLength = sizeof(ULONG);
RmtNode.Options = 0; // or TDI_QUERY_ACCEPT;
RmtNode.RemoteAddressLength = 0;
RmtNode.RemoteAddress = NULL;
//RmtNode.RemoteAddressLength = sizeof(RmtIPAddr);
//RmtNode.RemoteAddress = &RmtIPAddr;

// add the IP connection data to the IRP
TdiBuildListen( pIrp,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
NULL, // I/O completion routine.
NULL, // Context for I/O completion routine.
0, // or TDI_QUERY_ACCEPT, // Address of timeout interval.
&RmtNode, // Remote-node client address.
&RcvNode // (Output) remote-node address.
);

ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IoSetCompletionRoutine( pIrp, TDICompletionRoutine, &ListenEvent, TRUE, TRUE, TRUE);

ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
status = IoCallDriver(pTcpDevObj, pIrp);

if (STATUS_PENDING==status)
{
DbgPrint(“Waiting on IRP (Listen)…”);
status = KeWaitForSingleObject(&ListenEvent, Executive, KernelMode, FALSE, NULL);
}

if (STATUS_SUCCESS==status)
DbgPrint(“Listen Success …”);
else {
DbgPrint(“IoCallDriver failed (connect), status 0x%08X”, status);
return STATUS_UNSUCCESSFUL;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Accept an incoming request
/////////////////////////////////////////////////////////////////////////////////////////

KeInitializeEvent(&AcceptEvent, NotificationEvent, FALSE);

// build an IRP to listen
pIrp = TdiBuildInternalDeviceControlIrp(TDI_ACCEPT,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
&AcceptEvent, // Event to be signalled when Irp completes.
&IoStatus // I/O status block.
);

if(NULL==pIrp)
{
DbgPrint(“Could not get an IRP for TDI_ACCEPT”);
return(STATUS_INSUFFICIENT_RESOURCES);
}

// Initialize the IP address structure
RemotePort = HTONS(6000);
RemoteAddr = INETADDR(10,6,21,20); //do some r&d

RmtIPAddr.TAAddressCount = 1;
RmtIPAddr.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
RmtIPAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
RmtIPAddr.Address[0].Address[0].sin_port = RemotePort;
RmtIPAddr.Address[0].Address[0].in_addr = RemoteAddr;

RmtNode.UserDataLength = 0;
RmtNode.UserData = 0;
RmtNode.OptionsLength = 0;
RmtNode.Options = 0;
RmtNode.RemoteAddressLength = 0;
RmtNode.RemoteAddress = NULL;
// RmtNode.RemoteAddressLength = sizeof(RmtIPAddr);
// RmtNode.RemoteAddress = &RmtIPAddr;

DbgPrint(“Before tdiBuildAccept”);
// add the IP connection data to the IRP
TdiBuildAccept( pIrp,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
NULL, // I/O completion routine.
NULL, // Context for I/O completion routine.
&RmtNode, // Remote-node client address.
&RcvNode // (Output) remote-node address.
);

ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IoSetCompletionRoutine( pIrp, TDICompletionRoutine, &AcceptEvent, TRUE, TRUE, TRUE);

ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
status = IoCallDriver(pTcpDevObj, pIrp);

if (STATUS_PENDING==status)
{
DbgPrint(“Waiting on IRP (Accept)…”);
status = KeWaitForSingleObject(&AcceptEvent, Executive, KernelMode, FALSE, 0);
}

if (STATUS_SUCCESS==status)
DbgPrint(“Accept Success …”);
else
{
DbgPrint(“IoCallDriver failed (connect), status 0x%08X”, status);
return STATUS_UNSUCCESSFUL;
}

//////////////////////////////////////////////////////////////////////////////////////
// Step 4! We receive some data from the remote server…
//////////////////////////////////////////////////////////////////////////////////////
KeInitializeEvent(&RecvEvent, NotificationEvent, FALSE);

RecvBfrLength = strlen(RecvBfr);

pRecvBuffer = ExAllocatePool(NonPagedPool, RecvBfrLength);
memcpy(pRecvBuffer, RecvBfr, RecvBfrLength);

// build an IRP to connect to a remote host
pIrp =
TdiBuildInternalDeviceControlIrp( TDI_RECEIVE,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
&RecvEvent, // Event to be signalled when Irp completes.
&IoStatus // I/O status block.
);

if(NULL==pIrp)
{
DbgPrint(“Could not get an IRP for TDI_RECEIVE”);
return(STATUS_INSUFFICIENT_RESOURCES);
}

// must run at <= DISPATCH_LEVEL
ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
pMdl = IoAllocateMdl(pRecvBuffer, RecvBfrLength, FALSE, FALSE, pIrp);
if(NULL==pMdl)
{
DbgPrint(“Could not get an MDL for TDI_RECEIVE”);
return(STATUS_INSUFFICIENT_RESOURCES);
}

// must run at < DISPATCH_LEVEL for pageable memory
ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
__try
{
MmProbeAndLockPages( pMdl, // (Try to) fix buffer.
KernelMode,
IoModifyAccess
);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint(“Exception calling MmProbeAndLockPages”);
return STATUS_UNSUCCESSFUL;
}

DbgPrint(“Before tdiBuildRecv”);
TdiBuildReceive( pIrp,
pTcpDevObj, // TDI driver’s device object.
pConnFileObj, // Connection (endpoint) file object.
NULL, // I/O completion routine.
NULL, // Context for I/O completion routine.
pMdl, // MDL address.
0, // Flags. 0 => send as normal TSDU.
RecvBfrLength // Length of buffer mapped by MDL.
);
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IoSetCompletionRoutine( pIrp, TDICompletionRoutine, &RecvEvent, TRUE, TRUE, TRUE);

ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
status = IoCallDriver(pTcpDevObj, pIrp);
if (STATUS_PENDING==status)
{
DbgPrint(“Waiting on IRP (recv)…”);
KeWaitForSingleObject(&RecvEvent, Executive, KernelMode, FALSE, 0);
}

if ((STATUS_SUCCESS!=status)
&&
(STATUS_PENDING!=status))
{
//something is wrong
DbgPrint(“IoCallDriver failed (recv), status 0x%08X”, status);
return STATUS_UNSUCCESSFUL;
}

if ((STATUS_PENDING==status)
&&
(STATUS_SUCCESS!=IoStatus.Status))
{
//something is wrong
DbgPrint(“Completion of IRP failed (send), status 0x%08X”, IoStatus.Status);
return STATUS_UNSUCCESSFUL;
}

return STATUS_SUCCESS;
}</tdikrnl.h></ntddk.h>