windows-nt/Source/XPSP1/NT/termsrv/drivers/td/tdicom/tdilib.c
2020-09-26 16:20:57 +08:00

1118 lines
27 KiB
C

/*************************************************************************
* tdlib.c
*
* TDI library functions.
*
* Copyright 1998 Microsoft
*************************************************************************/
/*
* Includes
*/
#include <ntddk.h>
#include <tdi.h>
#include <tdikrnl.h>
#include "tdtdi.h"
#include <winstaw.h>
#define _DEFCHARINFO_
#include <icadd.h>
#include <ctxdd.h>
#include <sdapi.h>
#include <td.h>
#define _TDI_POLL_TIMEOUT (30 * 1000) // 30 seconds
#define _TDI_CONNECT_TIMEOUT 45
#define _TDI_DISCONNECT_TIMEOUT 60
#if DBG
ULONG
DbgPrint(
PCH Format,
...
);
#define DBGPRINT(x) DbgPrint x
#if DBGTRACE
#define TRACE0(x) DbgPrint x
#define TRACE1(x) DbgPrint x
#else
#define TRACE0(x)
#define TRACE1(x)
#endif
#else
#define DBGPRINT(x)
#define TRACE0(x)
#define TRACE1(x)
#endif
/*
* To use TDI:
*
* To connect to a remote server:
*
* Create Address EndPoint
*
* Create Connection Object
*
* Associate the Address EndPoint with the Connection Object
*
* Do a Connect
*
* To receive connections:
*
* Create Address EndPoint
*
* Create Connection Object
*
* Associate the Address EndPoint with the Connection Object
*
* Listen for a connection.
*
* Return connection
*/
/*
* Global data
*/
//
// Wait for xx seconds before polling on thread deletion.
//
ULONG
_TdiPollTimeout = _TDI_POLL_TIMEOUT;
/*
* Forward references
*/
PIRP
_TdiAllocateIrp(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL
);
NTSTATUS
_TdiRequestComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Ctx
);
NTSTATUS
_TdiSetEventHandler (
IN PTD pTd,
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject,
IN ULONG EventType,
IN PVOID EventHandler,
IN PVOID EventContext
);
NTSTATUS
_TdiSubmitRequest (
IN PTD pTd,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN BOOLEAN bKeepLock
);
/*
* External references
*/
NTSTATUS MemoryAllocate( ULONG, PVOID * );
VOID MemoryFree( PVOID );
BOOLEAN
PsIsThreadTerminating(
IN PETHREAD Thread
);
/*
* Functions
*/
NTSTATUS
_TdiCreateAddress (
IN PUNICODE_STRING pTransportName,
IN PVOID TdiAddress,
IN ULONG TdiAddressLength,
OUT PHANDLE pHandle,
OUT PFILE_OBJECT *ppFileObject,
OUT PDEVICE_OBJECT *ppDeviceObject
)
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES AddressAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_FULL_EA_INFORMATION EABuffer;
PDEVICE_OBJECT DeviceObject;
HANDLE TdiHandle = NULL;
PFILE_OBJECT FileObject = NULL;
/*
* The TDI interfaces uses an EA of name "TdiTransportName"
* to specify the structure TA_ADDRESS.
*/
Status = MemoryAllocate( (sizeof(FILE_FULL_EA_INFORMATION)-1 +
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
TdiAddressLength), &EABuffer);
if ( !NT_SUCCESS(Status) ) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
EABuffer->NextEntryOffset = 0;
EABuffer->Flags = 0;
EABuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
EABuffer->EaValueLength = (USHORT)TdiAddressLength;
// Copy in the EA name
RtlCopyMemory(EABuffer->EaName, TdiTransportAddress, EABuffer->EaNameLength+1);
// Copy the TA_ADDRESS parameter
RtlCopyMemory(&EABuffer->EaName[TDI_TRANSPORT_ADDRESS_LENGTH+1], TdiAddress,
EABuffer->EaValueLength);
TRACE0(("TdiCreateAddress Create endpoint of %wZ\n",pTransportName));
InitializeObjectAttributes (
&AddressAttributes,
pTransportName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE ,
NULL, // RootDirectory
NULL // SecurityDescriptor
);
Status = ZwCreateFile(
&TdiHandle, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&AddressAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
NULL, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
0, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
EABuffer, // EA Buffer
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
TdiAddressLength // EA length
);
MemoryFree(EABuffer);
if (!NT_SUCCESS(Status)) {
DBGPRINT(("TdiCreateAddress: Error Status 0x%x from function\n",Status));
return( Status );
}
if (!NT_SUCCESS(Status = IoStatusBlock.Status)) {
DBGPRINT(("TdiCreateAddress: Error Status 0x%x from Iosb\n",Status));
return( Status );
}
//
// Obtain a referenced pointer to the file object.
//
Status = ObReferenceObjectByHandle (
TdiHandle,
0,
*IoFileObjectType,
KernelMode,
(PVOID *)&FileObject,
NULL
);
if (!NT_SUCCESS(Status)) {
DBGPRINT(("TdiCreateAddress: Error Status 0x%x Referencing FileObject\n",Status));
goto error_cleanup;
}
//
// Get the address of the device object for the endpoint.
//
DeviceObject = IoGetRelatedDeviceObject(FileObject);
// Copy the out parameters
*pHandle = TdiHandle;
*ppFileObject = FileObject;
*ppDeviceObject = DeviceObject;
return STATUS_SUCCESS;
error_cleanup:
if ( FileObject != NULL ) {
ObDereferenceObject( FileObject );
}
if ( TdiHandle != NULL ) {
ZwClose( TdiHandle );
}
return Status;
}
NTSTATUS
_TdiOpenConnection (
IN PUNICODE_STRING pTransportName,
IN PVOID ConnectionContext,
OUT PHANDLE pHandle,
OUT PFILE_OBJECT *ppFileObject,
OUT PDEVICE_OBJECT *ppDeviceObject
)
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES AddressAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_FULL_EA_INFORMATION EABuffer;
CONNECTION_CONTEXT UNALIGNED *ContextPointer;
PDEVICE_OBJECT DeviceObject;
HANDLE ConnHandle = NULL;
PFILE_OBJECT FileObject = NULL;
Status = MemoryAllocate( (sizeof(FILE_FULL_EA_INFORMATION)-1 +
TDI_CONNECTION_CONTEXT_LENGTH+1 +
sizeof(CONNECTION_CONTEXT)), &EABuffer);
if( !NT_SUCCESS(Status) ) {
return( Status );
}
EABuffer->NextEntryOffset = 0;
EABuffer->Flags = 0;
EABuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
EABuffer->EaValueLength = sizeof(CONNECTION_CONTEXT);
// Copy in the EA name
RtlCopyMemory(EABuffer->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH+1);
// Copy in the EA data
ContextPointer =
(CONNECTION_CONTEXT UNALIGNED *)&EABuffer->EaName[TDI_CONNECTION_CONTEXT_LENGTH+1];
*ContextPointer = ConnectionContext;
TRACE0(("_TdiOpenConnection: Create connection object on transport %wZ\n",pTransportName));
InitializeObjectAttributes (&AddressAttributes,
pTransportName, // Name
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , // Attributes
NULL, // RootDirectory
NULL); // SecurityDescriptor
Status = ZwCreateFile(&ConnHandle, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&AddressAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
NULL, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
EABuffer, // EA Buffer
sizeof(FILE_FULL_EA_INFORMATION) +
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
sizeof(CONNECTION_CONTEXT));
MemoryFree(EABuffer);
if (!NT_SUCCESS(Status)) {
DBGPRINT(("_TdiOpenConnection: Error 0x%x Creating Connection object\n",Status));
return(Status);
}
Status = IoStatusBlock.Status;
if (!NT_SUCCESS(Status)) {
DBGPRINT(("_TdiOpenConnection: Error 0x%x Creating Connection object in Iosb\n",Status));
return(Status);
}
TRACE0(("_TdiOpenConnection: Returning connection handle %lx\n", ConnHandle));
//
// Obtain a referenced pointer to the file object.
//
Status = ObReferenceObjectByHandle (
ConnHandle,
0,
*IoFileObjectType,
KernelMode,
(PVOID *)&FileObject,
NULL
);
if (!NT_SUCCESS(Status)) {
DBGPRINT(("_TdiOpenConnection: Error Status 0x%x Referencing FileObject\n",Status));
ZwClose( ConnHandle );
return(Status);
}
//
// Get the address of the device object for the endpoint.
//
DeviceObject = IoGetRelatedDeviceObject(FileObject);
// Copy the out parameters
*pHandle = ConnHandle;
*ppFileObject = FileObject;
*ppDeviceObject = DeviceObject;
return(Status);
}
NTSTATUS
_TdiListen(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT ConnectionFileObject,
IN PDEVICE_OBJECT ConnectionDeviceObject
)
{
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
TDI_CONNECTION_INFORMATION RequestInfo;
TDI_CONNECTION_INFORMATION ReturnInfo;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
TdiBuildListen(
Irp,
ConnectionDeviceObject,
ConnectionFileObject,
NULL, // Completion routine
NULL, // Context
0, // Flags
&RequestInfo,
&ReturnInfo
);
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, FALSE);
TRACE0(("_TdiListen: Status 0x%x\n",Status));
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiAccept(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT ConnectionFileObject,
IN PDEVICE_OBJECT ConnectionDeviceObject
)
{
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
TDI_CONNECTION_INFORMATION RequestInfo;
TDI_CONNECTION_INFORMATION ReturnInfo;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
TdiBuildAccept(
Irp,
ConnectionDeviceObject,
ConnectionFileObject,
NULL, // Completion routine
NULL, // Context
&RequestInfo,
&ReturnInfo
);
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, FALSE);
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiConnect(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PLARGE_INTEGER pTimeout OPTIONAL,
IN PFILE_OBJECT ConnectionFileObject,
IN PDEVICE_OBJECT ConnectionDeviceObject,
IN ULONG RemoteTransportAddressLength,
IN PTRANSPORT_ADDRESS pRemoteTransportAddress
)
{
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
TDI_CONNECTION_INFORMATION RequestInfo;
TDI_CONNECTION_INFORMATION ReturnInfo;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
RequestInfo.RemoteAddressLength = RemoteTransportAddressLength;
RequestInfo.RemoteAddress = pRemoteTransportAddress;
TdiBuildConnect(
Irp,
ConnectionDeviceObject,
ConnectionFileObject,
NULL, // Completion routine
NULL, // Context
pTimeout,
&RequestInfo,
&ReturnInfo
);
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, TRUE);
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiAssociateAddress(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT ConnectionFileObject,
IN HANDLE AddressHandle,
IN PDEVICE_OBJECT AddressDeviceObject
)
{
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( ConnectionFileObject, AddressDeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
TdiBuildAssociateAddress(
Irp,
AddressDeviceObject,
ConnectionFileObject,
NULL, // Completion routine
NULL, // Context
AddressHandle
);
Status = _TdiSubmitRequest(pTd, AddressDeviceObject, Irp, FALSE);
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiDisconnect(
IN PTD pTd,
IN PFILE_OBJECT ConnectionFileObject,
IN PDEVICE_OBJECT ConnectionDeviceObject
)
{
PIRP Irp;
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
TdiBuildDisconnect(
Irp,
ConnectionDeviceObject,
ConnectionFileObject,
NULL, // Completion routine
NULL, // Context
0,
TDI_DISCONNECT_ABORT,
NULL,
NULL
);
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, TRUE);
IoFreeIrp( Irp );
return(Status);
}
NTSTATUS
_TdiSetEventHandler (
IN PTD pTd,
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject,
IN ULONG EventType,
IN PVOID EventHandler,
IN PVOID EventContext
)
/*++
Routine Description:
This routine registers an event handler with a TDI transport provider.
Arguments:
IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
IN ULONG EventType, - Supplies the type of event.
IN PVOID EventHandler - Supplies the event handler.
IN PVOID EventContext - Supplies the context for the event handler.
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
NTSTATUS Status;
PIRP Irp;
Irp = _TdiAllocateIrp( FileObject, NULL );
if (Irp == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
NULL, NULL,
EventType, EventHandler, EventContext);
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
IoFreeIrp( Irp );
return Status;
}
NTSTATUS
_TdiSubmitRequest (
IN PTD pTd,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN BOOLEAN bKeepLock
)
/*++
Routine Description:
This routine submits a request to TDI and waits for it to complete.
Arguments:
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
IN PIRP Irp - TDI request to submit.
Return Value:
NTSTATUS - Final status of request.
--*/
{
NTSTATUS Status;
PKEVENT Event;
Status = MemoryAllocate( sizeof(KEVENT), &Event );
if( !NT_SUCCESS(Status) ) {
return( Status );
}
KeInitializeEvent (Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, _TdiRequestComplete, Event, TRUE, TRUE, TRUE);
//
// Submit the request
//
Status = IoCallDriver(DeviceObject, Irp);
//
// If it failed immediately, return now, otherwise wait.
//
if (!NT_SUCCESS(Status)) {
DBGPRINT(("_TdiSubmitRequest: submit request. Status = %X", Status));
MemoryFree( Event );
return Status;
}
if (Status == STATUS_PENDING) {
TRACE0(("TDI request issued, waiting..."));
do {
//
// Wait for a couple of seconds for the request to complete
//
// If it times out, and the thread is terminating, cancel the
// request and unwind that way.
//
if ( !bKeepLock ) {
Status = IcaWaitForSingleObject(
pTd->pContext,
Event,
_TdiPollTimeout
);
} else {
LARGE_INTEGER WaitTimeout;
PLARGE_INTEGER pWaitTimeout = NULL;
WaitTimeout = RtlEnlargedIntegerMultiply( _TdiPollTimeout, -10000 );
pWaitTimeout = &WaitTimeout;
Status = KeWaitForSingleObject(
Event,
UserRequest,
UserMode,
FALSE,
pWaitTimeout
);
}
TRACE0(("_TdiSubmitRequest: Status 0x%x from IcaWaitForSingleObject\n",Status));
//
// If we timed out the wait, and the thread is terminating,
// give up and cancel the IRP.
//
if ( (Status == STATUS_TIMEOUT)
&&
ARGUMENT_PRESENT(Irp)
&&
PsIsThreadTerminating( Irp->Tail.Overlay.Thread ) ) {
//
// Ask the I/O system to cancel this IRP. This will cause
// everything to unwind properly.
//
DBGPRINT(("_TdiSubmitRequest: Irp being canceled\n"));
IoCancelIrp(Irp);
}
} while ( Status == STATUS_TIMEOUT );
if (!NT_SUCCESS(Status)) {
DBGPRINT(("Could not wait for connection to complete\n"));
MemoryFree( Event );
return Status;
}
Status = Irp->IoStatus.Status;
}
TRACE0(("TDI request complete Status 0x%x\n",Status));
MemoryFree( Event );
return(Status);
}
NTSTATUS
_TdiRequestComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Ctx
)
/*++
Routine Description:
Completion routine for _TdiRequestSubmit operation.
Arguments:
IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
IN PIRP Irp, - Supplies the IRP submitted
IN PVOID Context - Supplies a pointer to the kernel event to release
Return Value:
NTSTATUS - Status of KeSetEvent
We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
code from processing this puppy any more.
--*/
{
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DeviceObject);
TRACE0(("_TdiRequestComplete: Context %lx\n", Ctx));
//
// Set the event to the Signalled state with 0 priority increment and
// indicate that we will not be blocking soon.
//
KeSetEvent((PKEVENT) Ctx, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
PIRP
_TdiAllocateIrp(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
/*++
Routine Description:
This function allocates and builds an I/O request packet.
Arguments:
FileObject - Supplies a pointer to the file object for which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The redir accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
DeviceObject - Supplies a pointer to a device object to direct this
request to. If this is not supplied, it uses the file object to
determine the device object.
Return Value:
PIRP - Returns a pointer to the constructed IRP.
--*/
{
PIRP Irp;
if (ARGUMENT_PRESENT(DeviceObject)) {
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
} else {
Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
}
if (Irp == NULL) {
return(NULL);
}
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = KernelMode;
return Irp;
}
NTSTATUS
_TdiReceiveDatagram(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject,
IN PTRANSPORT_ADDRESS pRemoteAddress,
IN ULONG RemoteAddressLength,
IN ULONG RecvFlags,
IN PVOID pBuffer,
IN ULONG BufferLength,
OUT PULONG pReturnLength
)
{
PMDL pMdl;
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
TDI_CONNECTION_INFORMATION RequestInfo;
TDI_CONNECTION_INFORMATION ReturnInfo;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
// Copy in info to return remote address
ReturnInfo.RemoteAddress = pRemoteAddress;
ReturnInfo.RemoteAddressLength = RemoteAddressLength;
// Build MDL for buffer
pMdl = IoAllocateMdl(
pBuffer,
BufferLength,
FALSE,
FALSE,
(PIRP)NULL
);
if( pMdl == NULL ) {
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return( STATUS_INSUFFICIENT_RESOURCES );
}
MmBuildMdlForNonPagedPool ( pMdl );
TdiBuildReceiveDatagram(
Irp,
DeviceObject,
FileObject,
NULL, // Completion routine
NULL, // Context
pMdl, // Mdl address
BufferLength,
&RequestInfo,
&ReturnInfo,
RecvFlags // InFlags
);
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
IoFreeMdl( pMdl );
if ( NT_SUCCESS(Status) ) {
// Packet length returned is in the Iosb
*pReturnLength = (ULONG)Irp->IoStatus.Information;
TRACE0(("_TdiReceiveDatagram: Irp DataLength 0x%x UserDataLength 0x%x, "
"OptionsLength 0x%x, RemoteAddressLength 0x%x\n", *pReturnLength,
ReturnInfo.UserDataLength, ReturnInfo.OptionsLength,
ReturnInfo.RemoteAddressLength));
}
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiSendDatagram(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject,
IN PTRANSPORT_ADDRESS pRemoteAddress,
IN ULONG RemoteAddressLength,
IN PVOID pBuffer,
IN ULONG BufferLength
)
{
PMDL pMdl;
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
TDI_CONNECTION_INFORMATION SendInfo;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
RtlZeroMemory( &SendInfo, sizeof(SendInfo) );
// We must fill in our destination address
SendInfo.RemoteAddress = pRemoteAddress;
SendInfo.RemoteAddressLength = RemoteAddressLength;
// Build MDL for buffer
pMdl = IoAllocateMdl(
pBuffer,
BufferLength,
FALSE,
FALSE,
(PIRP)NULL
);
if( pMdl == NULL ) {
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return( STATUS_INSUFFICIENT_RESOURCES );
}
MmBuildMdlForNonPagedPool ( pMdl );
TdiBuildSendDatagram(
Irp,
DeviceObject,
FileObject,
NULL, // Completion routine
NULL, // Context
pMdl, // Mdl address
BufferLength,
&SendInfo
);
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
IoFreeMdl( pMdl );
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}
NTSTATUS
_TdiQueryAddressInfo(
IN PTD pTd,
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject,
IN PTDI_ADDRESS_INFO pAddressInfo,
IN ULONG AddressInfoLength
)
{
PMDL pMdl;
NTSTATUS Status;
BOOLEAN IrpAllocated = FALSE;
if (!ARGUMENT_PRESENT(Irp)) {
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
if (Irp == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
IrpAllocated = TRUE;
}
// Build MDL for buffer
pMdl = IoAllocateMdl(
pAddressInfo,
AddressInfoLength,
FALSE,
FALSE,
(PIRP)NULL
);
if( pMdl == NULL ) {
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return( STATUS_INSUFFICIENT_RESOURCES );
}
MmBuildMdlForNonPagedPool ( pMdl );
TdiBuildQueryInformation(
Irp,
DeviceObject,
FileObject,
NULL, // Completion routine
NULL, // Context
TDI_QUERY_ADDRESS_INFO,
pMdl
);
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
IoFreeMdl( pMdl );
if (IrpAllocated) {
IoFreeIrp( Irp );
}
return(Status);
}