/************************************************************************* * tdlib.c * * TDI library functions. * * Copyright 1998 Microsoft *************************************************************************/ /* * Includes */ #include #include #include #include "tdtdi.h" #include #define _DEFCHARINFO_ #include #include #include #include #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); }