/*++ Copyright (c) 1989 Microsoft Corporation Module Name: rxtdi.c Abstract: This module implements the NT TDI related routines used by RXCE. The wrappers are necessary to ensure that all the OS dependencies can be localized to select modules like this for customization. Revision History: Balan Sethu Raman [SethuR] 15-Feb-1995 Notes: --*/ #include "precomp.h" #pragma hdrstop #include "tdikrnl.h" #include "rxtdip.h" // // The debug trace level // #define Dbg (DEBUG_TRACE_RXCETDI) LARGE_INTEGER ConnectionTimeOut = {0,0}; #define CANCELLED_CONNECT_IRP IntToPtr(0xffffffff) #if DBG void DbgDumpTransportAddress( PWSTR RoutineName, PRXCE_TRANSPORT pTransport, PTRANSPORT_ADDRESS pTA ); #else #define DbgDumpTransportAddress( r, t, a ) #endif // Once a valid handle to a transport device object has been obtained subsequent // opens to the same device object can be opened with a NULL relative name to // this handle. This has two beneficial side effects --- one it is fast since // we do not have to go through the object manager's logic for parsing names and // in remote boot scenarios it minimizes the footprint that needs to be locked // down. UNICODE_STRING RelativeName = { 0,0,NULL}; NTSTATUS RxTdiBindToTransport( IN OUT PRXCE_TRANSPORT pTransport) /*++ Routine Description: This routine binds to the transport specified. Arguments: pTransport - the transport structure to be initialized pRxBindingContext - the binding context containing a pointer to the transport name and the quality of service for NT. Return Value: STATUS_SUCCESS - if the call was successfull. Notes: --*/ { NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES ChannelAttributes; IO_STATUS_BLOCK IoStatusBlock; RxProfile(RxTdi,RxTdiBindToTransport); InitializeObjectAttributes( &ChannelAttributes, // Tdi Control Channel attributes &pTransport->Name, // Name OBJ_CASE_INSENSITIVE, // Attributes NULL, // RootDirectory NULL); // SecurityDescriptor Status = ZwCreateFile( &pTransport->ControlChannel, // Handle GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access &ChannelAttributes, // Object Attributes &IoStatusBlock, // Final I/O status block 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // Normal attributes FILE_SHARE_READ, // Sharing attributes FILE_OPEN_IF, // Create disposition 0, // CreateOptions NULL, // EA Buffer 0); // EA length if (NT_SUCCESS(Status)) { // Obtain a referenced pointer to the file object. Status = ObReferenceObjectByHandle( pTransport->ControlChannel, // Object Handle FILE_ANY_ACCESS, // Desired Access NULL, // Object Type KernelMode, // Processor mode (PVOID *)&pTransport->pControlChannelFileObject,// Object pointer NULL); // Object Handle information if (NT_SUCCESS(Status)) { PIRP pIrp = NULL; // Obtain the related device object. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject); pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { PMDL pMdl; // Obtain the provider information from the specified transport. ASSERT(pTransport->pProviderInfo != NULL); pMdl = RxAllocateMdl( pTransport->pProviderInfo, // Virtual address for MDL construction sizeof( RXCE_TRANSPORT_PROVIDER_INFO)); // size of the buffer if ( pMdl != NULL ) { try { MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess ); } except( EXCEPTION_EXECUTE_HANDLER ) { IoFreeMdl( pMdl ); Status = GetExceptionCode(); } if (Status == STATUS_SUCCESS) { TdiBuildQueryInformation( pIrp, pTransport->pDeviceObject, pTransport->pControlChannelFileObject, RxTdiRequestCompletion, // Completion routine NULL, // Completion context TDI_QUERY_PROVIDER_INFO, pMdl); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); MmUnlockPages(pMdl); IoFreeMdl(pMdl); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } RxCeFreeIrp(pIrp); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } } return Status; } NTSTATUS RxTdiUnbindFromTransport( IN OUT PRXCE_TRANSPORT pTransport) /*++ Routine Description: This routine unbinds to the transport specified. Arguments: pTransport - the transport structure Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; RxProfile(RxTdi,RxTdiUnbindFromTransport); // Dereference the control channel file object. if (pTransport->pControlChannelFileObject != NULL) { ObDereferenceObject(pTransport->pControlChannelFileObject); } // Close the control channel if (pTransport->ControlChannel != INVALID_HANDLE_VALUE) { Status = ZwClose(pTransport->ControlChannel); } pTransport->pControlChannelFileObject = NULL; pTransport->ControlChannel = INVALID_HANDLE_VALUE; return Status; } NTSTATUS RxTdiOpenAddress( IN PRXCE_TRANSPORT pTransport, IN PTRANSPORT_ADDRESS pTransportAddress, IN OUT PRXCE_ADDRESS pAddress) /*++ Routine Description: This routine opens an address object. Arguments: Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES AddressAttributes; IO_STATUS_BLOCK IoStatusBlock; ULONG TransportAddressLength; ULONG TransportEaBufferLength; PFILE_FULL_EA_INFORMATION pTransportAddressEa; RxProfile(RxTdi,RxTdiOpenAddress); TransportAddressLength = ComputeTransportAddressLength(pTransportAddress); // Build an EA buffer for the specified transport address Status = BuildEaBuffer( TDI_TRANSPORT_ADDRESS_LENGTH, TdiTransportAddress, TransportAddressLength, pTransportAddress, &pTransportAddressEa, &TransportEaBufferLength); if (!NT_SUCCESS(Status)) { return Status; } InitializeObjectAttributes( &AddressAttributes, // OBJECT_ATTRIBUTES instance &RelativeName, // Name 0, // Attributes pTransport->ControlChannel, // RootDirectory NULL); // SecurityDescriptor Status = ZwCreateFile( &pAddress->hAddress, // Handle GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access &AddressAttributes, // Object Attributes &IoStatusBlock, // Final I/O status block 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // Normal attributes FILE_SHARE_READ, // Sharing attributes FILE_OPEN_IF, // Create disposition 0, // CreateOptions pTransportAddressEa, // EA Buffer TransportEaBufferLength); // EA length if (NT_SUCCESS(Status)) { // Obtain a referenced pointer to the file object. Status = ObReferenceObjectByHandle ( pAddress->hAddress, // Object Handle FILE_ANY_ACCESS, // Desired Access NULL, // Object Type KernelMode, // Processor mode (PVOID *)&pAddress->pFileObject, // Object pointer NULL); // Object Handle information Status = RxTdiSetEventHandlers(pTransport,pAddress); //DbgPrint("RDR opened address %lx\n", pAddress->hAddress); } // Free up the EA buffer allocated. RxFreePool(pTransportAddressEa); RxDbgTrace(0, Dbg,("RxTdiOpenAddress returns %lx\n",Status)); return Status; } NTSTATUS RxTdiSetEventHandlers( PRXCE_TRANSPORT pTransport, PRXCE_ADDRESS pRxCeAddress) /*++ Routine Description: This routine establishes the event handlers for a given address. Arguments: pRxCeAddress - the address object Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status; PIRP pIrp; RxProfile(RxTdi,RxTdiSetEventHandlers); pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // The event handlers need to be set one at a time. do { // Connect Event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_CONNECT, RxTdiConnectEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } // Disconnect event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_DISCONNECT, RxTdiDisconnectEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } // Error event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_ERROR, RxTdiErrorEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } // Receive Event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_RECEIVE, RxTdiReceiveEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } #if 0 // Receive datagram event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_RECEIVE_DATAGRAM, RxTdiReceiveDatagramEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } #endif // Receieve expedited event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_RECEIVE_EXPEDITED, RxTdiReceiveExpeditedEventHandler, pRxCeAddress); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); if (!NT_SUCCESS(Status)) { continue; } #if 0 // Send possible event handler TdiBuildSetEventHandler( pIrp, pTransport->pDeviceObject, pRxCeAddress->pFileObject, NULL, NULL, TDI_EVENT_SEND_POSSIBLE, RxTdiSendPossibleEventHandler, RxCeGetAddressHandle(pRxCeAddress)); Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp); #endif if (NT_SUCCESS(Status)) { // All the event handlers have been successfully set. break; } } while (NT_SUCCESS(Status)); // Free the Irp RxCeFreeIrp(pIrp); return Status; } NTSTATUS RxTdiConnect( IN PRXCE_TRANSPORT pTransport, IN OUT PRXCE_ADDRESS pAddress, IN OUT PRXCE_CONNECTION pConnection, IN OUT PRXCE_VC pVc) /*++ Routine Description: This routine establishes a connection between a local connection endpoint and a remote transport address. Arguments: pTransport - the associated transport pAddress - the address object to be closed pConnection - the RxCe connection instance pVc - the RxCe virtual circuit instance. Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES VcAttributes; IO_STATUS_BLOCK IoStatusBlock; PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL; ULONG ConnectionContextEaBufferLength; PFILE_FULL_EA_INFORMATION pConnectionContextEa; RxProfile(RxTdi,RxTdiConnect); #if DBG { PTRANSPORT_ADDRESS pTA = (PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress); RxDbgTrace(0, Dbg,("RxTdiConnect to %wZ address length %d type %d\n", &(pTransport->Name), pTA->Address[0].AddressLength, pTA->Address[0].AddressType )); } #endif // Build an EA buffer for the specified connection context Status = BuildEaBuffer( TDI_CONNECTION_CONTEXT_LENGTH, TdiConnectionContext, sizeof(PRXCE_VC), &pVc, &pConnectionContextEa, &ConnectionContextEaBufferLength); if (!NT_SUCCESS(Status)) { return Status; } // Open the local connection endpoint. InitializeObjectAttributes( &VcAttributes, // OBJECT_ATTRIBUTES instance &RelativeName, // Name 0, // Attributes pTransport->ControlChannel, // RootDirectory NULL); // SecurityDescriptor Status = ZwCreateFile( &pVc->hEndpoint, // Handle GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access &VcAttributes, // Object Attributes &IoStatusBlock, // Final I/O status block 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // Normal attributes FILE_SHARE_READ, // Sharing attributes FILE_OPEN_IF, // Create disposition 0, // CreateOptions pConnectionContextEa, // EA Buffer ConnectionContextEaBufferLength); // EA length if (NT_SUCCESS(Status)) { PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { // Obtain a referenced pointer to the file object. Status = ObReferenceObjectByHandle ( pVc->hEndpoint, // Object Handle FILE_ANY_ACCESS, // Desired Access NULL, // Object Type KernelMode, // Processor mode (PVOID *)&pVc->pEndpointFileObject, // Object pointer NULL); // Object Handle information if (NT_SUCCESS(Status)) { // Associate the local endpoint with the address object. TdiBuildAssociateAddress( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL, pAddress->hAddress); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (NT_SUCCESS(Status)) { // issue the connect request to the underlying transport provider. TdiBuildConnect( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL, &ConnectionTimeOut, pConnection->pConnectionInformation, pReturnConnectionInformation); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { // Disassociate address from the connection since the connect request was // not successful. NTSTATUS LocalStatus; TdiBuildDisassociateAddress( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL); LocalStatus = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); } else { // The associate address was not successful. RxDbgTrace(0, Dbg,("TDI connect returned %lx\n",Status)); } } else { // The associate address was not successful. RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status)); } if (!NT_SUCCESS(Status)) { // Dereference the endpoint file object. ObDereferenceObject(pVc->pEndpointFileObject); } } else { // error obtaining the file object for the connection. RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status)); } RxCeFreeIrp(pIrp); if (!NT_SUCCESS(Status)) { // Close the endpoint file object handle ZwClose(pVc->hEndpoint); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else { // error creating the connection object RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status)); } if (!NT_SUCCESS(Status)) { pVc->hEndpoint = INVALID_HANDLE_VALUE; pVc->pEndpointFileObject = NULL; } RxFreePool(pConnectionContextEa); return Status; } NTSTATUS RxTdiDereferenceAndFreeIrp( IN PULONG IrpRefCount, IN PIRP pIrp) /*++ Routine Description: This routine dereference the connect Irp and free it if ref count reaches 0 Arguments: pParameters - the connection parameters Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { ULONG RefCount; RefCount = InterlockedDecrement(IrpRefCount); if (RefCount == 0) { RxCeFreeIrp(pIrp); RxFreePool(IrpRefCount); } return STATUS_SUCCESS; } NTSTATUS RxTdiAsynchronousConnectCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context) /*++ Routine Description: This routine completes an asynchronous connect request. Arguments: pDeviceObject - the device object pIrp - the IRp Context - the completion context Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { PULONG IrpRefCount = NULL; PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters; RxDbgTrace(0, Dbg,("RxTdiAsynchronousConnectCompletion, irp 0x%x, status 0x%x\n", pIrp, pIrp->IoStatus.Status)); pParameters = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)Context; pParameters->CallOutStatus = pIrp->IoStatus.Status; IrpRefCount = pParameters->IrpRefCount; RxWmiLogError(pParameters->CallOutStatus, LOG, RxTdiAsynchronousConnectCompletion, LOGULONG(pParameters->CallOutStatus) LOGUSTR(pParameters->Connection.pAddress->pTransport->Name)); if (pParameters->pCallOutContext != NULL) { pParameters->pCallOutContext->pRxCallOutCompletion( (PRX_CALLOUT_PARAMETERS_BLOCK)pParameters); } // Free the IRP. RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp); return STATUS_MORE_PROCESSING_REQUIRED; UNREFERENCED_PARAMETER( DeviceObject ); } NTSTATUS RxTdiCancelAsynchronousConnect( IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters) /*++ Routine Description: This routine cancels a connection between a local connection endpoint and a remote transport address. Arguments: pParameters - the connection parameters Return Value: STATUS_CANCELLED - if the call was successfull. --*/ { KIRQL OldIrql; PIRP pIrp = NULL; PULONG IrpRefCount = NULL; BOOLEAN ShouldCancel = FALSE; NTSTATUS Status = STATUS_PENDING; KeAcquireSpinLock(&pParameters->pCallOutContext->SpinLock,&OldIrql); pIrp = InterlockedExchangePointer( &pParameters->pConnectIrp, CANCELLED_CONNECT_IRP); if ((pIrp != NULL) && (pIrp != CANCELLED_CONNECT_IRP)) { IrpRefCount = pParameters->IrpRefCount; (*IrpRefCount) ++; ShouldCancel = TRUE; } KeReleaseSpinLock(&pParameters->pCallOutContext->SpinLock,OldIrql); if (ShouldCancel) { if (IoCancelIrp(pIrp)) { Status = STATUS_CANCELLED; } RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp); } return Status; } NTSTATUS RxTdiCleanupAsynchronousConnect( IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters) /*++ Routine Description: This routine disconnects all failed requests when asynchronous connection attempts are made. Arguments: pParameters - the connection parameters Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; PIRP pIrp; PRXCE_CONNECTION pConnection; PRXCE_VC pVc; RxProfile(RxTdi,RxTdiConnect); pConnection = &pParameters->Connection; pVc = &pParameters->Vc; RxProfile(RxTdi,RxTdiDisconnect); if (pVc->pEndpointFileObject != NULL) { PDEVICE_OBJECT pDeviceObject; pDeviceObject = IoGetRelatedDeviceObject(pVc->pEndpointFileObject); pIrp = RxCeAllocateIrp(pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { TdiBuildDisassociateAddress( pIrp, pDeviceObject, pVc->pEndpointFileObject, NULL, NULL); Status = RxCeSubmitTdiRequest( pDeviceObject, pIrp); if (Status != STATUS_SUCCESS) { RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status)); } if (pParameters->CallOutStatus == STATUS_SUCCESS) { // Build the disconnect request to the underlying transport driver TdiBuildDisconnect( pIrp, // the IRP pDeviceObject, // the device object pVc->pEndpointFileObject, // the connection (VC) file object NULL, // Completion routine NULL, // completion context NULL, // time RXCE_DISCONNECT_ABORT, // disconnect options pConnection->pConnectionInformation, // disconnect request connection information NULL); // disconnect return connection information Status = RxCeSubmitTdiRequest( pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status)); } } RxCeFreeIrp(pIrp); } // Dereference the endpoint file object. ObDereferenceObject(pVc->pEndpointFileObject); // Close the endpoint file object handle ZwClose(pVc->hEndpoint); pVc->pEndpointFileObject = NULL; pVc->hEndpoint = INVALID_HANDLE_VALUE; } return STATUS_SUCCESS; } NTSTATUS RxTdiInitiateAsynchronousConnect( IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters) /*++ Routine Description: This routine establishes a connection between a local connection endpoint and a remote transport address. Arguments: pParameters - the connection parameters Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; PRXCE_TRANSPORT pTransport; PRXCE_ADDRESS pAddress; PRXCE_CONNECTION pConnection; PRXCE_VC pVc; OBJECT_ATTRIBUTES VcAttributes; IO_STATUS_BLOCK IoStatusBlock; PIRP pIrp = NULL; PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL; PFILE_FULL_EA_INFORMATION pConnectionContextEa; ULONG ConnectionContextEaBufferLength; PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pContext; RxProfile(RxTdi,RxTdiConnect); pConnection = &pParameters->Connection; pVc = &pParameters->Vc; pVc->hEndpoint = INVALID_HANDLE_VALUE; pVc->pEndpointFileObject = NULL; if (pParameters->pConnectIrp == CANCELLED_CONNECT_IRP) { return STATUS_CANCELLED; } pParameters->IrpRefCount = (PULONG)RxAllocatePoolWithTag( NonPagedPool, sizeof(ULONG), RXCE_CONNECTION_POOLTAG); if (pParameters->IrpRefCount == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } *(pParameters->IrpRefCount) = 1; pContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)pParameters->pCallOutContext; pAddress = pConnection->pAddress; pTransport = pAddress->pTransport; DbgDumpTransportAddress( L"RxInitiateAsynchronousConnect", pTransport, (PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress) ); // Build an EA buffer for the specified connection context Status = BuildEaBuffer( TDI_CONNECTION_CONTEXT_LENGTH, TdiConnectionContext, sizeof(PRXCE_VC), &pContext->pConnectionContext, &pConnectionContextEa, &ConnectionContextEaBufferLength); if (!NT_SUCCESS(Status)) { if (pParameters->IrpRefCount != NULL) { RxFreePool(pParameters->IrpRefCount); pParameters->IrpRefCount = NULL; } return Status; } // Open the local connection endpoint. InitializeObjectAttributes( &VcAttributes, // OBJECT_ATTRIBUTES instance &RelativeName, // Name 0, // Attributes pTransport->ControlChannel, // RootDirectory NULL); // SecurityDescriptor Status = ZwCreateFile( &pVc->hEndpoint, // Handle GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access &VcAttributes, // Object Attributes &IoStatusBlock, // Final I/O status block 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // Normal attributes FILE_SHARE_READ, // Sharing attributes FILE_OPEN_IF, // Create disposition 0, // CreateOptions pConnectionContextEa, // EA Buffer ConnectionContextEaBufferLength); // EA length // Free the connection context ea buffer. RxFreePool(pConnectionContextEa); if (NT_SUCCESS(Status)) { pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { // Obtain a referenced pointer to the file object. Status = ObReferenceObjectByHandle ( pVc->hEndpoint, // Object Handle FILE_ANY_ACCESS, // Desired Access NULL, // Object Type KernelMode, // Processor mode (PVOID *)&pVc->pEndpointFileObject, // Object pointer NULL); // Object Handle information if (NT_SUCCESS(Status)) { // Associate the local endpoint with the address object. TdiBuildAssociateAddress( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL, pAddress->hAddress); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (NT_SUCCESS(Status)) { // issue the connect request to the underlying transport provider. TdiBuildConnect( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL, &ConnectionTimeOut, pConnection->pConnectionInformation, pReturnConnectionInformation); IoSetCompletionRoutine( pIrp, // The IRP RxTdiAsynchronousConnectCompletion, // The completion routine pParameters, // The completion context TRUE, // Invoke On Success TRUE, // Invoke On Error TRUE); // Invoke On Cancel InterlockedExchangePointer( &pParameters->pConnectIrp, pIrp); // Submit the request Status = IoCallDriver( pTransport->pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { RxDbgTrace(0,Dbg,("RxTdiAsynchronousConnect: Connect IRP initiation failed, irp %lx, status 0x%x\n",pIrp, Status)); } Status = STATUS_PENDING; } else { // The associate address was not successful. RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status)); } } else { // error obtaining the file object for the connection. RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status)); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } if (Status != STATUS_PENDING) { if (pIrp != NULL) { RxCeFreeIrp(pIrp); } if (pParameters->IrpRefCount != NULL) { RxFreePool(pParameters->IrpRefCount); } if (pVc->pEndpointFileObject != NULL) { ObDereferenceObject(pVc->pEndpointFileObject); pVc->pEndpointFileObject = NULL; } if (pVc->hEndpoint != INVALID_HANDLE_VALUE) { // Close the endpoint file object handle ZwClose(pVc->hEndpoint); pVc->hEndpoint = INVALID_HANDLE_VALUE; } } } else { // error creating the connection object RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status)); if (pParameters->IrpRefCount != NULL) { RxFreePool(pParameters->IrpRefCount); pParameters->IrpRefCount = NULL; } } return Status; } NTSTATUS RxTdiReconnect( IN PRXCE_TRANSPORT pTransport, IN OUT PRXCE_ADDRESS pAddress, IN OUT PRXCE_CONNECTION pConnection, IN OUT PRXCE_VC pVc) /*++ Routine Description: This routine establishes a connection between a local connection endpoint and a remote transport address. Arguments: pTransport - the associated transport pAddress - the address object to be closed pConnection - the RxCe connection instance pVc - the RxCe virtual circuit instance. Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status; PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL; PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); RxProfile(RxTdi,RxTdiReconnect); ASSERT(pVc->State == RXCE_VC_DISCONNECTED); if (pIrp != NULL) { // issue the connect request to the underlying transport provider. TdiBuildConnect( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL, &ConnectionTimeOut, pConnection->pConnectionInformation, pReturnConnectionInformation); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (NT_SUCCESS(Status)) { InterlockedExchange( &pVc->State, RXCE_VC_ACTIVE); } else { // The reconnect request was not successful RxDbgTrace(0, Dbg,("RxTdiReconnect: TDI connect returned %lx\n",Status)); } RxCeFreeIrp(pIrp); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } return Status; } NTSTATUS RxTdiDisconnect( IN PRXCE_TRANSPORT pTransport, IN PRXCE_ADDRESS pAddress, IN PRXCE_CONNECTION pConnection, IN PRXCE_VC pVc, IN ULONG DisconnectFlags) /*++ Routine Description: This routine closes down a previously established connection. Arguments: pTransport - the associated transport pAddress - the address object pConnection - the connection pVc - the virtual circuit to be disconnected. DisconnectFlags - DisconnectOptions Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status; PIRP pIrp; RxProfile(RxTdi,RxTdiDisconnect); pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } TdiBuildDisassociateAddress( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, NULL, NULL); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (NT_SUCCESS(Status)) { // Build the disconnect request to the underlying transport driver TdiBuildDisconnect( pIrp, // the IRP pTransport->pDeviceObject, // the device object pVc->pEndpointFileObject, // the connection (VC) file object NULL, // Completion routine NULL, // completion context NULL, // time DisconnectFlags, // disconnect options pConnection->pConnectionInformation, // disconnect request connection information NULL); // disconnect return connection information Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status)); } } else { RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status)); } RxCeFreeIrp(pIrp); return STATUS_SUCCESS; } NTSTATUS RxTdiCloseAddress( IN OUT PRXCE_ADDRESS pAddress) /*++ Routine Description: This routine closes the address object. Arguments: pRxCeAddress - the address object to be closed Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; // Dereference the file object. if (pAddress->pFileObject != NULL) { ObDereferenceObject(pAddress->pFileObject); } // Close the address file object handle ZwClose(pAddress->hAddress); //DbgPrint("RDR closed address %lx\n", pAddress->hAddress); return Status; } NTSTATUS RxTdiQueryInformation( IN PRXCE_TRANSPORT pTransport, IN PRXCE_ADDRESS pAddress, IN PRXCE_CONNECTION pConnection, IN PRXCE_VC pVc, IN ULONG QueryType, IN PVOID pQueryBuffer, IN ULONG QueryBufferLength) /*++ Routine Description: This routine queries the information w.r.t a connection Arguments: pTransport - the associated transport pAddress - the address object to be closed pConnection - the RxCe connection instance pVc - the VC instance QueryType - the class of information desired pQueryBuffer - the buffer in whihc the data is to be returned QueryBufferLength - the query buffer length. Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; PIRP pIrp = NULL; // Obtain the related device object. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject); pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { PMDL pMdl; pMdl = RxAllocateMdl( pQueryBuffer, // Virtual address for MDL construction QueryBufferLength); // size of the buffer if ( pMdl != NULL ) { try { MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess ); } except( EXCEPTION_EXECUTE_HANDLER ) { IoFreeMdl( pMdl ); Status = GetExceptionCode(); } if (Status == STATUS_SUCCESS) { // Get the file object associated with trhe connection. TdiBuildQueryInformation( pIrp, pTransport->pDeviceObject, pVc->pEndpointFileObject, RxTdiRequestCompletion, // Completion routine NULL, // Completion context QueryType, pMdl); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); MmUnlockPages(pMdl); IoFreeMdl(pMdl); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } RxCeFreeIrp(pIrp); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } return Status; } NTSTATUS RxTdiQueryAdapterStatus( IN PRXCE_TRANSPORT pTransport, IN PADAPTER_STATUS pAdapterStatus) /*++ Routine Description: This routine queries the information w.r.t a connection Arguments: pTransport - the associated transport pAdapterStatus - ADAPTER STATUS structure Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; PIRP pIrp = NULL; if (pTransport->pControlChannelFileObject != NULL) { // Obtain the related device object. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject); pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { PMDL pMdl; pMdl = RxAllocateMdl( pAdapterStatus, // Virtual address for MDL construction sizeof(ADAPTER_STATUS)); // size of the buffer if ( pMdl != NULL ) { try { MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess ); } except( EXCEPTION_EXECUTE_HANDLER ) { IoFreeMdl( pMdl ); Status = GetExceptionCode(); } if (NT_SUCCESS(Status)) { // Get the file object associated with the connection. TdiBuildQueryInformation( pIrp, pTransport->pDeviceObject, pTransport->pControlChannelFileObject, NULL, // Completion routine NULL, // Completion context TDI_QUERY_ADAPTER_STATUS, pMdl); Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); MmUnlockPages(pMdl); IoFreeMdl(pMdl); } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } RxCeFreeIrp(pIrp); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else { Status = STATUS_ADDRESS_NOT_ASSOCIATED; } return Status; } NTSTATUS RxTdiSend( IN PRXCE_TRANSPORT pTransport, IN PRXCE_ADDRESS pAddress, IN PRXCE_CONNECTION pConnection, IN PRXCE_VC pVc, IN ULONG SendOptions, IN PMDL pMdl, IN ULONG SendLength, IN PVOID pCompletionContext) /*++ Routine Description: This routine closes down a previously established connection. Arguments: pTransport - the associated transport pAddress - the address object pConnection - the connection pVc - the virtual circuit to be disconnected. SendOptions - the options for transmitting the data pMdl - the buffer to be transmitted. SendLength - length of data to be transmitted Return Value: STATUS_SUCCESS - if the call was successfull. --*/ { NTSTATUS Status = STATUS_SUCCESS; PMDL pPartialMdl = NULL; ULONG MdlByteCount = MmGetMdlByteCount(pMdl); PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl); ULONG TdiOptions = (~RXCE_FLAGS_MASK & SendOptions); BOOLEAN SynchronousSend = ((SendOptions & RXCE_SEND_SYNCHRONOUS) != 0); RxProfile(RxTdi,RxTdiSend); ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL)); if (SendOptions & RXCE_SEND_PARTIAL) { if (MdlByteCount > SendLength) { pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL); if (pPartialMdl == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength); } } else if (MdlByteCount == SendLength) { // No need to build a partial MDL, reuse the MDl pPartialMdl = pMdl; } else { ASSERT(!"MdlByteCount > SendLength"); return STATUS_INVALID_PARAMETER; } } else { pPartialMdl = pMdl; } if (NT_SUCCESS(Status)) { PIRP pIrp = NULL; PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext = NULL; pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { // Build the Send request to the underlying transport driver TdiBuildSend( pIrp, // the IRP pTransport->pDeviceObject, // the device object pVc->pEndpointFileObject, // the connection (VC) file object NULL, // Completion routine NULL, // completion context pPartialMdl, // the data buffer TdiOptions, // send flags SendLength); // send buffer length if (SynchronousSend) { // Synchronous Send Request Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); if ((pConnection->pHandler != NULL) && (pConnection->pHandler->RxCeSendCompleteEventHandler != NULL)) { (pConnection->pHandler->RxCeSendCompleteEventHandler)( pConnection->pContext, pVc, pCompletionContext, pIrp->IoStatus.Status); } } else { // Aysnchronous Send Request // CODE.IMPROVEMENT The assertion needs to be strengthened after // max command enfocement is in place. // (pCompletionContext != NULL) && // the caller provided a valid context ASSERT((pConnection->pHandler != NULL) && // the connection has a handler (pConnection->pHandler->RxCeSendCompleteEventHandler != NULL)); pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT) RxAllocatePoolWithTag( NonPagedPool, sizeof(RXTDI_REQUEST_COMPLETION_CONTEXT), RXCE_TDI_POOLTAG); if (pRequestContext != NULL) { if (pPartialMdl != pMdl) { pRequestContext->pPartialMdl = pPartialMdl; } else { pRequestContext->pPartialMdl = NULL; } pRequestContext->pVc = pVc; pRequestContext->pCompletionContext = pCompletionContext; pRequestContext->ConnectionSendCompletionHandler = pConnection->pHandler->RxCeSendCompleteEventHandler; pRequestContext->pEventContext = pConnection->pContext; Status = RxCeSubmitAsynchronousTdiRequest( pTransport->pDeviceObject, pIrp, pRequestContext); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } } else { // Could not allocate the IRP. Status = STATUS_INSUFFICIENT_RESOURCES; } if (SynchronousSend) { if (pPartialMdl != pMdl) { IoFreeMdl( pPartialMdl ); } if (pRequestContext != NULL) { RxFreePool(pRequestContext); } if (pIrp != NULL) { RxCeFreeIrp(pIrp); } } else { if( Status != STATUS_PENDING && pPartialMdl != pMdl ) { IoFreeMdl( pPartialMdl ); } // if (pIrp != NULL && Status != STATUS_PENDING) { // DbgPrint("RDBSS AsyncSendReq returned %x %x\n", pIrp,Status); // DbgBreakPoint(); // } } } return Status; } NTSTATUS RxTdiSendDatagram( IN PRXCE_TRANSPORT pTransport, IN PRXCE_ADDRESS pAddress, IN PRXCE_CONNECTION_INFORMATION pConnectionInformation, IN ULONG Options, IN PMDL pMdl, IN ULONG SendLength, IN PVOID pCompletionContext) /*++ Routine Description: This routine closes down a previously established connection. Arguments: pTransport - the associated transport pAddress - the address object pConnectionInformation - the remote address Options - the send options. pMdl - the send buffer SendLength - length of data to be sent Return Value: STATUS_SUCCESS - if the call was successfull. Notes: In the current implementation the SYNCHRONOUS flag is disregarded for sending datagrams because the underlying transports do not block on datagram sends. Submission of request and completion of request happen simultaneously. If a different behaviour is noted for some transports then the code for SendDatagrams need to be implemented along the lines of a send. --*/ { NTSTATUS Status = STATUS_SUCCESS; PMDL pPartialMdl = NULL; ULONG MdlByteCount = MmGetMdlByteCount(pMdl); PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl); ULONG TdiOptions = (~RXCE_FLAGS_MASK & Options); RxProfile(RxTdi,RxTdiSendDatagram); ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL)); DbgDumpTransportAddress( L"RxTdiSendDatagram", pTransport, (PTRANSPORT_ADDRESS)(pConnectionInformation->RemoteAddress) ); if (Options & RXCE_SEND_PARTIAL) { if (MdlByteCount > SendLength) { pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL); if (pPartialMdl == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength); } } else if (MdlByteCount == SendLength) { // No need to build a partial MDL, reuse the MDl pPartialMdl = pMdl; } else { RxDbgTrace(0, Dbg,("Mdl Length - %lx Send Length %lx\n",MdlByteCount,SendLength)); ASSERT(!"MdlByteCount > SendLength"); Status = STATUS_INVALID_PARAMETER; } } else { pPartialMdl = pMdl; } if (NT_SUCCESS(Status)) { PIRP pIrp; pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { // Build the disconnect request to the underlying transport driver TdiBuildSendDatagram( pIrp, // the IRP pTransport->pDeviceObject, // the device object pAddress->pFileObject, // the connection (VC) file object NULL, // Completion routine NULL, // completion context pPartialMdl, // the send data buffer SendLength, // the send data buffer length pConnectionInformation); // remote address information Status = RxCeSubmitTdiRequest( pTransport->pDeviceObject, pIrp); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } if ((pAddress->pHandler != NULL) && (pAddress->pHandler->RxCeSendCompleteEventHandler != NULL)) { (pAddress->pHandler->RxCeSendCompleteEventHandler)( pAddress->pContext, pCompletionContext, Status); } if (pIrp != NULL) { RxCeFreeIrp(pIrp); } if ((pPartialMdl != pMdl) && (pPartialMdl != NULL)) { IoFreeMdl( pPartialMdl ); } } return Status; } NTSTATUS RxTdiRequestCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This routine does not complete the Irp. It is used to signal to a synchronous part of the driver that it can proceed. Arguments: DeviceObject - unused. Irp - Supplies Irp that the transport has finished processing. Context - Supplies the event associated with the Irp. Return Value: The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops processing Irp stack locations at this point. --*/ { RxDbgTrace(0, Dbg, ("CompletionEvent\n")); if (Context != NULL) KeSetEvent((PKEVENT )Context, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; UNREFERENCED_PARAMETER( DeviceObject ); UNREFERENCED_PARAMETER( Irp ); } NTSTATUS RxCeSubmitTdiRequest ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: This routine submits a request to TDI and waits for it to complete. Arguments: IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request IN PIRP Irp - TDI request to submit. Return Value: NTSTATUS - Final status of request. --*/ { NTSTATUS Status; KEVENT Event; KeInitializeEvent ( &Event, NotificationEvent, FALSE); IoSetCompletionRoutine( pIrp, // The IRP RxTdiRequestCompletion, // The completion routine &Event, // The completion context TRUE, // Invoke On Success TRUE, // Invoke On Error TRUE); // Invoke On Cancel // // Submit the request // RxDbgTrace(0, Dbg,("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject)); Status = IoCallDriver(pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status)); } if ((Status == STATUS_PENDING) || (Status == STATUS_SUCCESS)) { RxDbgTrace(0, Dbg,("Waiting for Tdi Request Completion ....\n")); Status = KeWaitForSingleObject( &Event, // Object to wait on. Executive, // Reason for waiting KernelMode, // Processor mode FALSE, // Alertable NULL); // Timeout if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg,("RxTdiSubmitRequest could not wait Wait returned %lx\n",Status)); return Status; } Status = pIrp->IoStatus.Status; } else { if (!KeReadStateEvent(&Event)) { DbgBreakPoint(); } } RxDbgTrace(0, Dbg, ("RxCeSubmitTdiRequest returned %lx\n",Status)); return Status; } NTSTATUS RxTdiAsynchronousRequestCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ) /*++ Routine Description: This routine completes an asynchronous send request. Arguments: DeviceObject - unused. Irp - Supplies Irp that the transport has finished processing. Context - Supplies the event associated with the Irp. Return Value: The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops processing Irp stack locations at this point. --*/ { PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext; RxDbgTrace(0, Dbg,("RxTdiAsynchronousRequestCompletion\n")); pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT)Context; if (pRequestContext->pPartialMdl != NULL) { // Free the partial MDL. IoFreeMdl(pRequestContext->pPartialMdl); } // Invoke the Completion event handler if any. if (pRequestContext->pVc == NULL) { if (pRequestContext->SendCompletionHandler != NULL) { (pRequestContext->SendCompletionHandler)( pRequestContext->pEventContext, pRequestContext->pCompletionContext, pIrp->IoStatus.Status); } } else { if (pRequestContext->ConnectionSendCompletionHandler != NULL) { (pRequestContext->ConnectionSendCompletionHandler)( pRequestContext->pEventContext, pRequestContext->pVc, pRequestContext->pCompletionContext, pIrp->IoStatus.Status); } } // Free the IRP. RxCeFreeIrp(pIrp); // Free the request context RxFreePool(pRequestContext); return STATUS_MORE_PROCESSING_REQUIRED; UNREFERENCED_PARAMETER( DeviceObject ); } NTSTATUS RxCeSubmitAsynchronousTdiRequest ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext ) /*++ Routine Description: This routine submits a request to TDI and waits for it to complete. Arguments: IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request IN PIRP Irp - TDI request to submit. Return Value: NTSTATUS - Final status of request. --*/ { NTSTATUS Status; ASSERT(pRequestContext != NULL); IoSetCompletionRoutine( pIrp, // The IRP RxTdiAsynchronousRequestCompletion, // The completion routine pRequestContext, // The completion context TRUE, // Invoke On Success TRUE, // Invoke On Error TRUE); // Invoke On Cancel // // Submit the request // RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject)); Status = IoCallDriver(pDeviceObject, pIrp); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status)); } RxDbgTrace(0, Dbg, ("RxCeSubmitAsynchronousTdiRequest returned %lx\n",Status)); return Status; } NTSTATUS BuildEaBuffer ( IN ULONG EaNameLength, IN PVOID pEaName, IN ULONG EaValueLength, IN PVOID pEaValue, OUT PFILE_FULL_EA_INFORMATION *pEaBufferPointer, OUT PULONG pEaBufferLength ) /*++ Routine Description: Builds an EA buffer. Arguments: EaNameLength - Length of the Extended attribute name pEaName - the extended attriute name EaValueLength - Length of the Extended attribute value pEaValue - the extended attribute value pBuffer - the buffer for constructing the EA --*/ { PFILE_FULL_EA_INFORMATION pEaBuffer; ULONG Length; RxDbgTrace(0, Dbg, ("BuildEaBuffer\n")); // Allocate an EA buffer for passing down the transport address *pEaBufferLength = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) + EaNameLength + 1 + EaValueLength; pEaBuffer = (PFILE_FULL_EA_INFORMATION) RxAllocatePoolWithTag( PagedPool, *pEaBufferLength, RXCE_TDI_POOLTAG); if (pEaBuffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } *pEaBufferPointer = pEaBuffer; pEaBuffer->NextEntryOffset = 0; pEaBuffer->Flags = 0; pEaBuffer->EaNameLength = (UCHAR)EaNameLength; pEaBuffer->EaValueLength = (USHORT)EaValueLength; RtlCopyMemory ( pEaBuffer->EaName, pEaName, pEaBuffer->EaNameLength + 1); RtlCopyMemory( &pEaBuffer->EaName[EaNameLength + 1], pEaValue, EaValueLength); return STATUS_SUCCESS; } NTSTATUS RxTdiCancelConnect( IN PRXCE_TRANSPORT pTransport, IN PRXCE_ADDRESS pAddress, IN PRXCE_CONNECTION pConnection) { return STATUS_NOT_IMPLEMENTED; } #if DBG void DbgDumpTransportAddress( PWSTR RoutineName, PRXCE_TRANSPORT pTransport, PTRANSPORT_ADDRESS pTA ) /*++ Routine Description: Description Arguments: None Return Value: None --*/ { ULONG i; PTA_ADDRESS taa; RxDbgTrace(0, Dbg,("%ws on %wZ, address count = %d\n", RoutineName, &(pTransport->Name), pTA->TAAddressCount) ); taa = pTA->Address; for( i = 0; i < (ULONG) pTA->TAAddressCount; i++ ){ RxDbgTrace(0, Dbg, ("\t%d:Address length %d type %d: ", i, taa->AddressLength, taa->AddressType )); switch (taa->AddressType) { case TDI_ADDRESS_TYPE_NETBIOS_EX: { PTDI_ADDRESS_NETBIOS_EX address = (PTDI_ADDRESS_NETBIOS_EX) taa->Address; RxDbgTrace( 0, Dbg, ("Endpoint: \"%16.16s\" type %d name \"%16.16s\"\n", address->EndpointName, address->NetbiosAddress.NetbiosNameType, address->NetbiosAddress.NetbiosName) ); break; } case TDI_ADDRESS_TYPE_NETBIOS: { PTDI_ADDRESS_NETBIOS address = (PTDI_ADDRESS_NETBIOS) taa->Address; RxDbgTrace( 0, Dbg, ("NBType %d name \"%16.16s\"\n", address->NetbiosNameType, address->NetbiosName) ); break; } case TDI_ADDRESS_TYPE_IP: { PTDI_ADDRESS_IP address = (PTDI_ADDRESS_IP) taa->Address; RxDbgTrace( 0, Dbg, ("IP port %d addr 0x%x\n", address->sin_port, address->in_addr ) ); break; } default: { RxDbgTrace( 0, Dbg, ("Unknown!\n") ); } } taa = (PTA_ADDRESS) (taa->Address + taa->AddressLength); } } #endif