www.pudn.com > VSer.rar > TDIClient.c
/*++
Copyright (c) 2005 Changzhi Zhou All Rights Reserved
Module Name:
TDIClient.c
Abstract:
This module contains the routines relevant to TDI client calls.
Environment:
Kernel mode
Revision History:
Changzhi Zhou Feb 5, 2005
--*/
#include "TDIClient.h"
#include "main.h"
NTSTATUS InitializeConnection( PDEVICE_EXTENSION deviceExtension )
/*++
Routine Description:
1. Open a transport address and get the highest deviceobject of the transport stack.
2. Build RecvContext in the DeviceExtension
3. SetTdiEventHandle, includes TDI_EVENT_RECEIVE_DATAGRAM and TDI_EVENT_ERROR
Arguments:
deviceExtension - pointer to a device object extension.
Return Value:
NT status code.
--*/
{
NTSTATUS status;
static USHORT Port = LOCAL_PORT;
if ( ( deviceExtension->hTransAddr ) || ( deviceExtension->lpTransAddrFileObject ) )
return STATUS_INVALID_DEVICE_STATE;
status = TDIOpenTransportAddress( wcharNetDevName,
&deviceExtension->hTransAddr,
&deviceExtension->lpTransAddrFileObject,
Port
);
DebugPrint(("OpenTransAddr: handle = %x, lpFileObj = %x, status = %x\n",
deviceExtension->hTransAddr, deviceExtension->lpTransAddrFileObject, status ));
if ( status != STATUS_SUCCESS )
{
deviceExtension->lpTransAddrFileObject = NULL;
deviceExtension->hTransAddr = NULL;
return status;
}
Port += 0x100;
deviceExtension->TDILowerDeviceObject = IoGetRelatedDeviceObject( deviceExtension->lpTransAddrFileObject );
DebugPrint(("TDI Provider: 0x%x\n", deviceExtension->TDILowerDeviceObject ));
if ( deviceExtension->TDILowerDeviceObject == NULL )
{
ObDereferenceObject ( deviceExtension->lpTransAddrFileObject );
ZwClose ( deviceExtension->hTransAddr );
deviceExtension->lpTransAddrFileObject = NULL;
deviceExtension->hTransAddr = NULL;
return STATUS_UNSUCCESSFUL;
}
TDIBuildRecvContext( &deviceExtension->recvContext );
TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
deviceExtension->TDILowerDeviceObject, TDI_EVENT_RECEIVE_DATAGRAM,
TDIEventRecvDatagram, deviceExtension );
TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
deviceExtension->TDILowerDeviceObject, TDI_EVENT_ERROR,
TDIEventError, NULL );
return status;
}
NTSTATUS Disconnection ( PDEVICE_EXTENSION deviceExtension )
/*++
Routine Description:
1. SetTdiEventhandle TDI_EVENT_RECEIVE_DATAGRAM to NULL
2. Free RecvContext in the DeviceExtension
3. Close an opened transport address.
3. SetTdiEventHandle, includes TDI_EVENT_RECEIVE_DATAGRAM and TDI_EVENT_ERROR
Arguments:
deviceExtension - pointer to a device object extension.
Return Value:
NT status code.
--*/
{
NTSTATUS status;
if ( ( deviceExtension->hTransAddr == NULL ) || ( deviceExtension->lpTransAddrFileObject == NULL ) )
return STATUS_INVALID_DEVICE_STATE;
TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
deviceExtension->TDILowerDeviceObject, TDI_EVENT_RECEIVE_DATAGRAM,
NULL, deviceExtension );
TDIFreeRecvContext( &deviceExtension->recvContext );
ObDereferenceObject ( deviceExtension->lpTransAddrFileObject );
deviceExtension->lpTransAddrFileObject = NULL;
status = ZwClose ( deviceExtension->hTransAddr );
if ( status == STATUS_SUCCESS )
deviceExtension->hTransAddr = NULL;
else
{
DebugPrint(("ZwClose hTransAddr failed with status %x !\n", status ));
}
return status;
}
NTSTATUS TDISendDatagram(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This function is called in SampleWrite. It builds a internel irp and send down
to the underlying transport. Until the irp completes or timeout, it will return.
The remote peer's IP address and port are indicated by RemoteAddress and
RemotePort in deviceExtension.
1. TdiBuildInternalDeviceControlIrp for TDI_SEND_DATAGRAM
2. Allocate and lockpage a MDL based on Irp->MdlAddress
3. TdiBuildSendDatagram and pass down to the underlying transport device.
4. Wait 3 seconds for the completion. If timeout, cancel the irp
5. Set the Irp according with the completed irp.
Note:
This routine is synchronous.
It must be running at IRQL = PASSIVE_LEVEL
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet for IRP_MJ_WRITE.
Return Value:
NT status code.
--*/
{
NTSTATUS status;
PIRP pIrp;
PDEVICE_EXTENSION deviceExtension;
KEVENT Event;
IO_STATUS_BLOCK IoStatus;
PMDL pMdl;
PVOID VirtualAddress;
ULONG Length;
EXCEPTION_POINTERS * pExceptionInfo;
ULONG lclExceptionCode;
PVOID lclExceptionAddr;
PVOID SystemAddress;
TA_IP_ADDRESS RmtAddress = {1, {TDI_ADDRESS_LENGTH_IP, TDI_ADDRESS_TYPE_IP, { REMOTE_PORT, REMOTE_ADDRESS}}};
TDI_CONNECTION_INFORMATION RmtInfo = {0, 0, 0, 0, sizeof(RmtAddress), &RmtAddress};
deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
RmtAddress.Address->Address->sin_port = deviceExtension->RemotePort;
RmtAddress.Address->Address->in_addr = deviceExtension->RemoteAddress;
status = STATUS_SUCCESS;
KeInitializeEvent( &Event, NotificationEvent, FALSE);
pIrp = TdiBuildInternalDeviceControlIrp(
TDI_SEND_DATAGRAM,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
&Event,
&IoStatus );
if ( NULL == pIrp )
{
DebugPrint(("TDISendDatagram: Allocate Irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
VirtualAddress = MmGetMdlVirtualAddress ( Irp->MdlAddress );
Length = MmGetMdlByteCount( Irp->MdlAddress );
ASSERT ( VirtualAddress && Length );
pMdl = IoAllocateMdl ( VirtualAddress, Length, FALSE, FALSE, pIrp );
if ( NULL == pMdl )
{
DebugPrint(("TDISendDatagram: Allocate Mdl failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
_try
{
MmProbeAndLockPages(pMdl, // (Try to) fix buffer.
KernelMode,
IoModifyAccess
);
}
_except(
pExceptionInfo = GetExceptionInformation(),
lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,
lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,
EXCEPTION_EXECUTE_HANDLER
)
{
DebugPrint((".TDISendDatagram: MmProbeAndLockPages() failed. Error = 0x%08x at 0x%08x\n",
lclExceptionCode, lclExceptionAddr));
status = STATUS_UNSUCCESSFUL;
IoFreeMdl ( pMdl );
CompleteRequest ( pIrp, status, 0 );
Irp->IoStatus.Information = 0;
return status;
}
TdiBuildSendDatagram(
pIrp,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
NULL,
NULL,
pMdl,
Length,
&RmtInfo
);
status = IoCallDriver ( deviceExtension->TDILowerDeviceObject, pIrp );
if( ( status != STATUS_SUCCESS ) || ( STATUS_PENDING != status ) )
{
DebugPrint(("TDISendDatagram: Problem in IoCallDriver with status %x\n", status ));
}
if ( status == STATUS_PENDING )
{
LARGE_INTEGER TimeOut;
NTSTATUS waitStatus;
DebugPrint(("Send data pending... wait for 3 seconds\n"));
TimeOut.QuadPart = -30000 * 1000; // Calculate timeout value (5 seconds from now).
waitStatus = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, &TimeOut);
if ( STATUS_TIMEOUT == waitStatus )
{
DebugPrint(("TDISendDatagram: Send data time out...\n"));
IoCancelIrp ( pIrp );
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, 0);
}
}
Irp->IoStatus.Information = IoStatus.Information;
DebugPrint(("TDISendDatagram: Send %d bytes\n", Irp->IoStatus.Information ));
status = ((STATUS_SUCCESS==status) || (STATUS_PENDING== status)) ? IoStatus.Status : status;
return status;
}
NTSTATUS TDIEventError(
IN PVOID TdiEventContext, // The endpoint's file object.
IN NTSTATUS Status // Status code indicating error type.
)
/*++
Tdi error handle.
--*/
{
DebugPrint(("Sample ErrorEventHandler: Status: 0x%8.8X\n", Status) );
return( STATUS_SUCCESS );
}
NTSTATUS TDIEventRecvDatagram(
IN PVOID TdiEventContext,
IN LONG SourceAddressLength,
IN PVOID SourceAddress,
IN LONG OptionsLength,
IN PVOID Options,
IN ULONG ReceiveDatagramFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
/*++
Routine Description:
TDI_EVENT_RECEIVE_DATAGRAM handle.
When a UDP packet from particular address and port arrive, this callback function will be called.
Usually BytesIndicated is less than or equal to BytesAvailable. If less, a Irp should be buildt
for the remainder data. This irp has be pre-allocated by TDIBuildRecvContext.
Note:
Don't forget to call IoSetNextIrpStackLocation to handle the IoRequestPacket.
Because the stack locations of this irp between this function and underlying transport are identical.
Pls refer to Windows DDK documentation chapter relevant to this handle.
--*/
{
LONG i;
PUCHAR p;
PIRP pIrp;
NTSTATUS status;
ULONG BytesToCopy;
ULONG stageSize;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = (PDEVICE_EXTENSION)TdiEventContext;
DebugPrint(("SourceAddress: "));
p = (PUCHAR)SourceAddress;
for( i = 0; i < SourceAddressLength; i++)
{
DbgPrint("%2x ", p[ i ] );
}
DbgPrint(("\n"));
DebugPrint(("ReceiveDatagramFlags: %x\n", ReceiveDatagramFlags ));
DebugPrint(("BytesIndicated: %d\n", BytesIndicated ));
DebugPrint(("BytesAvailable: %d\n", BytesAvailable ));
*BytesTaken = BytesIndicated;
CopyToRingBuffer( deviceExtension, (PUCHAR)Tsdu, BytesIndicated );
*IoRequestPacket = NULL;
status = STATUS_SUCCESS;
if ( BytesIndicated < BytesAvailable )
{
if ( deviceExtension->recvContext.pIrp )
{
pIrp = deviceExtension->recvContext.pIrp;
DebugPrint(("EventRecvDatagram: pIrp = %x\n", deviceExtension->recvContext.pIrp ));
TdiBuildReceiveDatagram( pIrp,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
TDIRecvRemainderCompRoutine,
deviceExtension,
deviceExtension->recvContext.pMdl,
0,
&(deviceExtension->recvContext.ReceiveDatagramInfo),
&(deviceExtension->recvContext.ReturnInfo),
TDI_RECEIVE_NORMAL);
IoSetNextIrpStackLocation ( pIrp );
*IoRequestPacket = pIrp;
status = STATUS_MORE_PROCESSING_REQUIRED;
}
}
return status;
}
VOID CopyToRingBuffer(
PDEVICE_EXTENSION deviceExtension,
PUCHAR LinearBuffer,
ULONG BytesIndicated )
/*++
Routine Description:
This function is called by TDIEventRecvDatagram and TDIRecvRemainderCompRoutine.
It copies linear buffer containing network packet to ring buffer. If source buffer length
is more than the length of ReceiveBuffer, the last part of LinearBuffer will be copied
to destination buffer.
If there is WaitOnMaskIrp in deviceExtension and the WaitMask meets SERIAL_EV_RXCHAR || SERIAL_EV_RLSD,
it will complete the WaitOnMaskIrp to indicate the application that there are some data arrive.
The destination ringbuffer, deviceExtension->RxBuffer, is shared with IRP_MJ_READ.
So the access to the ringbuffer must be synchronous.
Arguments:
deviceExtension - pointer to device object extension
LinearBuffer - Tsdu containing network packets.
BytesIndicated - the length of LinearBuffer
Return Value:
NT status code.
--*/
{
ULONG stageSize;
KIRQL oldIrql;
ULONG BytesToCopy;
PUCHAR lpSrc;
BytesToCopy = BytesIndicated;
lpSrc = LinearBuffer;
if ( BytesIndicated > RINGBUFFER_SIZE )
{
lpSrc = (PUCHAR)LinearBuffer + BytesIndicated - RINGBUFFER_SIZE;
BytesToCopy = RINGBUFFER_SIZE;
}
KeAcquireSpinLock(&deviceExtension->ThreadSpinLock, &oldIrql);
stageSize = deviceExtension->RxBuffer + RINGBUFFER_SIZE - deviceExtension->lpRx;
if( BytesToCopy <= stageSize )
RtlCopyMemory ( deviceExtension->lpRx, lpSrc, BytesToCopy );
else
{
RtlCopyMemory ( deviceExtension->lpRx, lpSrc, stageSize );
RtlCopyMemory ( deviceExtension->RxBuffer, lpSrc + stageSize, ( BytesToCopy - stageSize ) );
}
deviceExtension->lpRx = deviceExtension->RxBuffer + ( ( RINGBUFFER_SIZE - stageSize + BytesToCopy ) % RINGBUFFER_SIZE );
deviceExtension->SerialStatus.AmountInInQueue += BytesToCopy;
if ( deviceExtension->SerialStatus.AmountInInQueue > RINGBUFFER_SIZE )
{
deviceExtension->lpRead = deviceExtension->lpRx;
deviceExtension->SerialStatus.AmountInInQueue = RINGBUFFER_SIZE;
}
if( ( deviceExtension->WaitOnMaskIrp ) &&
( ( deviceExtension->WaitMask & SERIAL_EV_RXCHAR ) || ( deviceExtension->WaitMask & SERIAL_EV_RLSD ) ) )
{
DebugPrint(("ClientEventRecv: Complete WaitOnMaskIrp\n"));
deviceExtension->SerialStatus.EofReceived = TRUE;
*(PULONG)deviceExtension->WaitOnMaskIrp->AssociatedIrp.SystemBuffer = ( SERIAL_EV_RXCHAR | SERIAL_EV_RLSD );
CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_SUCCESS, sizeof( ULONG ) );
deviceExtension->WaitOnMaskIrp = NULL;
SampleIoDecrement( deviceExtension );
}
KeReleaseSpinLock( &deviceExtension->ThreadSpinLock, oldIrql );
}
NTSTATUS TDIBuildRecvContext( PRECV_CONTEXT lpContext)
/*++
Routine Description:
This function is called by InitializeConnection.
It builds RecvContext, including pIrp, pMdl, and locks the Mdl.
Arguments:
lpContext - pointer to deviceExtension->recvContext
Return Value:
NT status code.
--*/
{
PIRP pIrp;
PMDL pMdl;
PDEVICE_EXTENSION deviceExtension;
EXCEPTION_POINTERS * pExceptionInfo;
ULONG lclExceptionCode;
PVOID lclExceptionAddr;
PIO_STACK_LOCATION ioStack;
if( lpContext->pIrp || lpContext->pMdl || ( lpContext->RemainderBuffer == NULL ) )
return STATUS_UNSUCCESSFUL;
deviceExtension = CONTAINING_RECORD( lpContext, DEVICE_EXTENSION, recvContext );
pIrp = IoAllocateIrp ( deviceExtension->TDILowerDeviceObject->StackSize + 2, FALSE );
/*
Because the irp will be used for many times, TdiBuildInternalDeviceControlIrp is not best.
*/
/* pIrp = TdiBuildInternalDeviceControlIrp(
TDI_RECEIVE_DATAGRAM,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
&lpContext->Event,
&lpContext->IoStatus
);
*/
if (NULL == pIrp)
{
DebugPrint(("TdiBuildInternalIrp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}else
{
DebugPrint(("TDIBuildRecvContext: pIrp = %x\n", pIrp ));
}
pMdl = IoAllocateMdl ( lpContext->RemainderBuffer,
RECVREMAINDER_BUFFER_SIZE, FALSE, FALSE, NULL );
if (NULL==pMdl)
{
goto Error_Exit;
}
_try
{
// lockpage the Mdl, even though it is allocated based on NonPagesPool
MmProbeAndLockPages(pMdl, // (Try to) fix buffer.
KernelMode,
IoModifyAccess
);
lpContext->bLocked = TRUE;
DebugPrint(("RemainderBuffer: 0x%x, pMdl: 0x%x\n", lpContext->RemainderBuffer, pMdl ));
}
_except(
pExceptionInfo = GetExceptionInformation(),
lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,
lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,
EXCEPTION_EXECUTE_HANDLER
)
{
DebugPrint((".TDIClnRecv: MmProbeAndLockPages() failed. Error = 0x%08x at 0x%08x\n",
lclExceptionCode, lclExceptionAddr));
goto Error_Exit;
}
lpContext->pIrp = pIrp;
lpContext->pMdl = pMdl;
return STATUS_SUCCESS;
Error_Exit:
if ( pMdl )
IoFreeMdl ( pMdl );
if ( pIrp )
IoFreeIrp ( pIrp );
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
TDIRecvRemainderCompRoutine(
PDEVICE_OBJECT DeviceObject, // TDI driver's device object.
PIRP pIrp, // Address of completed Irp.
PVOID pCtx // Pointer to context.
)
/*++
Routine Description:
Completion routine of IoRequestPacket in TDIEventRecvDatagram.
It copies receiving data in recvContext.RemainderBuffer to RxBuffer.
The length of receining data is indicated by pIrp->IoStatus.Information.
Arguments:
DeviceObject - pointer to the device object
pIrp - pointer to completed Irp, which is recvContext->pIrp
pCtx - pointer to context, which is deviceExtension
Return Value:
NT status code.
--*/
{
PDEVICE_EXTENSION deviceExtension;
PRECV_CONTEXT lpContext;
ULONG RecvDataLength;
PUCHAR lpSrc;
DebugPrint(("TDIRecvRemainderCompRoutine...\n"));
RecvDataLength = pIrp->IoStatus.Information;
deviceExtension = (PDEVICE_EXTENSION)pCtx;
DebugPrint(("Remainder length: %d\n", RecvDataLength ));
CopyToRingBuffer ( deviceExtension,
(PUCHAR)deviceExtension->recvContext.RemainderBuffer,
RecvDataLength );
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS TDIFreeRecvContext( PRECV_CONTEXT lpContext )
/*++
Routine Description:
Free recvContext.
Arguments:
lpContext - pointer to recvContext.
Return Value:
NT status code.
--*/
{
if ( lpContext->pIrp )
{
IoFreeIrp ( lpContext->pIrp );
lpContext->pIrp = NULL;
}
if ( lpContext->bLocked )
{
MmUnlockPages ( lpContext->pMdl );
lpContext->bLocked = FALSE;
}
if ( lpContext->pMdl )
{
IoFreeMdl ( lpContext->pMdl );
lpContext->pMdl = NULL;
}
return STATUS_SUCCESS;
}
/**************************************************************************************************/
/* */
/* Build and send down an Irp for Receive. */
/* */
/* Notes: */
/* 1) This routine is NOT synchronous (no particular reason it's not, other than to show */
/* off asynchronous operation of an Irp). */
/* */
/* 2) There are indications that an MDL and probe-and-lock are needed even if the buffer */
/* is from the non-paged pool. Eg, microsoft.public.win32.programmer.kernel, */
/* "MmProbeAndLockPages bug checks," dave porter, 2001-03-02. But see the further */
/* discussion in comp.os.ms-windows.programmer.nt.kernel-mode, "Free MDL in completion */
/* routine," 1999/05/09. */
/* */
/* 3) Although not documented, it appears that the Irp, the Mdl and the locking are undone */
/* by the transport. There are claims to that effect in several places in newsgroups, */
/* and freeing the MDL always caused errors in a test (eg, bad pool caller or touching */
/* paged storage at wrong IRQL). Further, testing showed that IoFreeMdl() was being */
/* called by somebody (presumably, the transport) for a given MDL. */
/* */
/* 4) The supplied context (pCtx) is an event, which the I/O completion routine for the */
/* Receive Irp will signal. */
/* */
/**************************************************************************************************/
NTSTATUS TDIQueryNetworkInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp )
{
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION IrpStack;
IO_STATUS_BLOCK IoStatus;
NTSTATUS status;
ULONG InputLength, OutputLength;
ULONG QType;
PIRP pIrp;
KEVENT Event;
PMDL pMdl;
ULONG_PTR virtualAddress;
EXCEPTION_POINTERS * pExceptionInfo;
ULONG lclExceptionCode;
PVOID lclExceptionAddr;
BOOLEAN pageLocked;
deviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
QType = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
DebugPrint(("QueryNetworkInformation: QType = %x\n", QType ));
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pIrp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION ,
deviceExtension->TDILowerDeviceObject, // TDI driver's device object.
deviceExtension->lpTransAddrFileObject, // Address file object.
&Event, // Event to be signalled when Irp completes.
&IoStatus // I/O status block.
);
if (NULL==pIrp)
return STATUS_INSUFFICIENT_RESOURCES;
virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
OutputLength = MmGetMdlByteCount(Irp->MdlAddress);
pMdl = IoAllocateMdl( (PVOID)virtualAddress, OutputLength, FALSE, FALSE, NULL);
pageLocked = FALSE;
_try{
MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess );
pageLocked = TRUE;
}
_except(
pExceptionInfo = GetExceptionInformation(),
lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,
lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,
EXCEPTION_EXECUTE_HANDLER
)
{
DebugPrint((".TDIClnRecv: MmProbeAndLockPages() failed. Error = 0x%08x at 0x%08x\n",
lclExceptionCode, lclExceptionAddr));
status = lclExceptionCode;
goto done;
}
TdiBuildQueryInformation ( pIrp, deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
NULL, NULL, QType, pMdl );
status = IoCallDriver ( deviceExtension->TDILowerDeviceObject, pIrp );
if (STATUS_PENDING==status)
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
done:
status = ((STATUS_SUCCESS==status) || (STATUS_PENDING==status)) ? IoStatus.Status : status;
Irp->IoStatus.Information = IoStatus.Information;
DebugPrint(("QueryInfo: status %x, Info %d\n", status, Irp->IoStatus.Information ));
return status;
}
NTSTATUS
TDIClnSetEventHandler(
PFILE_OBJECT pAddrFileObj, // Address file object.
PDEVICE_OBJECT pTcpDevObj, // TDI driver's device object.
LONG EventType, // Type of event.
PVOID pEventHandler, // Event handler routine.
PVOID pEventContext // Context for event handler.
)
/**************************************************************************************************/
/* */
/* Set up an event handler. */
/* */
/* Note: This routine is synchronous. */
/* */
/**************************************************************************************************/
{
NTSTATUS status;
KEVENT Event;
IO_STATUS_BLOCK IoStatus;
PIRP pIrp;
do { // Single-iteration loop, to make possible escape via break.
KeInitializeEvent(&Event, NotificationEvent, FALSE);
// Get an Irp for internal device ioctl.
pIrp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER,
pTcpDevObj, // TDI driver's device object.
pAddrFileObj, // Address file object.
&Event, // Event to be signalled when Irp completes.
&IoStatus // I/O status block.
);
if (NULL==pIrp)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
TdiBuildSetEventHandler(pIrp,
pTcpDevObj,
pAddrFileObj,
NULL, // I/O completion routine.
NULL, // Context for I/O completion routine.
EventType,
pEventHandler, // Event handler routine.
pEventContext // Context for event handler routine.
);
status = IoCallDriver(pTcpDevObj, pIrp);
if (STATUS_PENDING==status) // Have to wait on this Irp?
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
// Problem from IoCallDriver() or Problem discovered in completion?
if ( ( STATUS_SUCCESS!=status && STATUS_PENDING!=status )
|| ( STATUS_PENDING==status && 0!=IoStatus.Status ) )
{
// Note: If problem was in IoCallDriver(), IoStatus.Status probably won't be meaningful.
DebugPrint(("TDIClnSetEventHandler: Problem in IoCallDriver(). status = 0x%08x, IoStatus.Status = 0x%08x\n",
STATUS_PENDING==status ? 0 : status , IoStatus.Status));
}
} while(0); // End 'do-while' single-iteration loop.
status = ((STATUS_SUCCESS==status) || (STATUS_PENDING==status)) ? IoStatus.Status : status;
return status;
} // End TDIClnSetEventHandler().
NTSTATUS
TDIOpenTransportAddress(
PWSTR pTransDevName, // Transport device name.
PHANDLE pHandle, // Output handle address.
PFILE_OBJECT * ppAddrFileObj, // Output address file object.
USHORT Port // Port to open.
)
/**************************************************************************************************/
/* */
/* Open transport address. */
/* */
/**************************************************************************************************/
{
NTSTATUS status;
UNICODE_STRING TransDeviceName;
OBJECT_ATTRIBUTES Attr;
IO_STATUS_BLOCK IoStatus;
PTA_IP_ADDRESS pSin;
PFILE_FULL_EA_INFORMATION pEa;
char Buffer[sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS)];
ASSERT ( *pHandle == NULL );
ASSERT ( *ppAddrFileObj == NULL );
RtlInitUnicodeString(&TransDeviceName, // Build Unicode transport device name.
pTransDevName
);
InitializeObjectAttributes(&Attr, // Attributes (to be initialized);
&TransDeviceName,
OBJ_CASE_INSENSITIVE
|
OBJ_KERNEL_HANDLE, // Only in kernel mode but in any process.
0,
0
);
pEa = (PFILE_FULL_EA_INFORMATION)Buffer;
pEa->NextEntryOffset= 0;
pEa->Flags = 0;
pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; // Length of TdiTransportAddress, namely of "TransportAddress" string less 1 (ie, without terminator).
RtlCopyMemory ( pEa->EaName, TdiTransportAddress, pEa->EaNameLength + 1 );
pEa->EaValueLength = sizeof(TA_IP_ADDRESS); // Length of structure.
// Point to Buffer just after what's been used (ie, after terminator).
pSin =(PTA_IP_ADDRESS) ( pEa->EaName + pEa->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 = Port;
pSin->Address[0].Address[0].in_addr = 0;//0x601a8c0; // 192.168.1.6
RtlZeroMemory ( pSin->Address[ 0 ].Address[ 0 ].sin_zero, sizeof ( pSin->Address[ 0 ].Address[ 0 ].sin_zero ) );
status = ZwCreateFile(pHandle, // Actual open of transport address.
GENERIC_READ | GENERIC_WRITE,
&Attr,
&IoStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF,
0,
pEa, //NULL,
sizeof ( Buffer )
);
if (!NT_SUCCESS(status))
{
DebugPrint(("ZwCreateFile failed with status %x\n", status ));
return status;
}
status = ObReferenceObjectByHandle(*pHandle, // Get the object pointer for the address file object's handle.
GENERIC_READ | GENERIC_WRITE,
0,
KernelMode,
(PVOID *)ppAddrFileObj,
NULL
);
if (!NT_SUCCESS(status))
{
DebugPrint(("ObReferenceObject failed with status %x\n", status ));
ZwClose ( *pHandle );
*pHandle = NULL;
}
return status;
}