// // // NBTCONNCT.C // // This file contains code relating to opening connections with the transport // provider. The Code is NT specific. #include "precomp.h" //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma CTEMakePageable(PAGE, NbtTdiOpenConnection) #pragma CTEMakePageable(PAGE, NbtTdiAssociateConnection) #pragma CTEMakePageable(PAGE, NbtTdiCloseConnection) #pragma CTEMakePageable(PAGE, CreateDeviceString) #pragma CTEMakePageable(PAGE, NbtTdiCloseAddress) #endif //******************* Pageable Routine Declarations **************** //---------------------------------------------------------------------------- NTSTATUS NbtTdiOpenConnection ( IN tLOWERCONNECTION *pLowerConn, IN tDEVICECONTEXT *pDeviceContext ) /*++ Routine Description: This routine opens a connection with the transport provider. Arguments: pLowerConn - Pointer to where the handle to the Transport for this virtual connection should be stored. pNbtConfig - the name of the adapter to connect to is in this structure Return Value: Status of the operation. --*/ { IO_STATUS_BLOCK IoStatusBlock; NTSTATUS Status, Status1; OBJECT_ATTRIBUTES ObjectAttributes; PWSTR pName=L"Tcp"; PFILE_FULL_EA_INFORMATION EaBuffer; UNICODE_STRING RelativeDeviceName = {0,0,NULL}; PMDL pMdl; PVOID pBuffer; BOOLEAN Attached = FALSE; CTEPagedCode(); // zero out the connection data structure CTEZeroMemory(pLowerConn,sizeof(tLOWERCONNECTION)); SET_STATE_LOWER (pLowerConn, NBT_IDLE); pLowerConn->pDeviceContext = pDeviceContext; CTEInitLock(&pLowerConn->LockInfo.SpinLock); #if DBG pLowerConn->LockInfo.LockNumber = LOWERCON_LOCK; #endif pLowerConn->Verify = NBT_VERIFY_LOWERCONN; // // Allocate an MDL for the Indication buffer since we may need to buffer // up to 128 bytes // pBuffer = NbtAllocMem(NBT_INDICATE_BUFFER_SIZE,NBT_TAG('l')); if (!pBuffer) { return(STATUS_INSUFFICIENT_RESOURCES); } pMdl = IoAllocateMdl(pBuffer,NBT_INDICATE_BUFFER_SIZE,FALSE,FALSE,NULL); if (pMdl) { MmBuildMdlForNonPagedPool(pMdl); pLowerConn->pIndicateMdl = pMdl; #ifdef HDL_FIX InitializeObjectAttributes (&ObjectAttributes, &RelativeDeviceName, OBJ_KERNEL_HANDLE, pDeviceContext->hSession, // Use a relative File Handle NULL); #else InitializeObjectAttributes (&ObjectAttributes, &RelativeDeviceName, 0, pDeviceContext->hSession, // Use a relative File Handle NULL); #endif // HDL_FIX // Allocate memory for the address info to be passed to the transport EaBuffer = (PFILE_FULL_EA_INFORMATION)NbtAllocMem ( sizeof(FILE_FULL_EA_INFORMATION) - 1 + TDI_CONNECTION_CONTEXT_LENGTH + 1 + sizeof(CONNECTION_CONTEXT),NBT_TAG('m')); if (EaBuffer) { EaBuffer->NextEntryOffset = 0; EaBuffer->Flags = 0; EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH; EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT); // TdiConnectionContext is a macro that = "ConnectionContext" - so move // this text to EaName RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 ); // put the context value into the EaBuffer too - i.e. the value that the // transport returns with each indication on this connection RtlMoveMemory ( (PVOID)&EaBuffer->EaName[EaBuffer->EaNameLength + 1], (CONST PVOID)&pLowerConn, sizeof (CONNECTION_CONTEXT)); { Status = ZwCreateFile (&pLowerConn->FileHandle, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes, // object attributes. &IoStatusBlock, // returned status information. NULL, // block size (unused). FILE_ATTRIBUTE_NORMAL, // file attributes. 0, FILE_CREATE, 0, // create options. (PVOID)EaBuffer, // EA buffer. sizeof(FILE_FULL_EA_INFORMATION) - 1 + TDI_CONNECTION_CONTEXT_LENGTH + 1 + sizeof(CONNECTION_CONTEXT)); } IF_DBG(NBT_DEBUG_HANDLES) KdPrint (("\t===><%x>\tNbtTdiOpenConnection->ZwCreateFile, Status = <%x>\n", pLowerConn->FileHandle, Status)); IF_DBG(NBT_DEBUG_TDICNCT) KdPrint( ("Nbt.NbtTdiOpenConnection: CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status)); CTEMemFree((PVOID)EaBuffer); if ( NT_SUCCESS( Status )) { // if the ZwCreate passed set the status to the IoStatus // Status = IoStatusBlock.Status; if (NT_SUCCESS(Status)) { // get a reference to the file object and save it since we can't // dereference a file handle at DPC level so we do it now and keep // the ptr around for later. Status = ObReferenceObjectByHandle (pLowerConn->FileHandle, 0L, NULL, KernelMode, (PVOID *)&pLowerConn->pFileObject, NULL); IF_DBG(NBT_DEBUG_HANDLES) KdPrint (("\t ++<%x>====><%x>\tNbtTdiOpenConnection->ObReferenceObjectByHandle, Status = <%x>\n", pLowerConn->FileHandle, pLowerConn->pFileObject, Status)); if (NT_SUCCESS(Status)) { #if FAST_DISP // Go ahead and query transport for fast dispath path. IF_DBG(NBT_DEBUG_TDICNCT) KdPrint(("Nbt.NbtTdiOpenConnection: Querying for TCPSendData File object %x\n",pLowerConn->pFileObject )); pLowerConn->FastSend = pDeviceContext->pFastSend; #endif return(Status); } Status1 = ZwClose(pLowerConn->FileHandle); IF_DBG(NBT_DEBUG_HANDLES) KdPrint (("\t<===<%x>\tNbtTdiOpenConnection->ZwClose, status = <%x>\n", pLowerConn->FileHandle, Status1)); } } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } IoFreeMdl(pMdl); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } CTEMemFree(pBuffer); return Status; } /* NbtTdiOpenConnection */ //---------------------------------------------------------------------------- NTSTATUS NbtTdiAssociateConnection( IN PFILE_OBJECT pFileObject, IN HANDLE Handle ) /*++ Routine Description: This routine associates an open connection with the address object. Arguments: pFileObject - the connection file object Handle - the address object to associate the connection with Return Value: Status of the operation. --*/ { NTSTATUS status; PIRP pIrp; KEVENT Event; BOOLEAN Attached = FALSE; CTEPagedCode(); KeInitializeEvent (&Event, SynchronizationEvent, FALSE); pIrp = NTAllocateNbtIrp(IoGetRelatedDeviceObject(pFileObject)); if (!pIrp) { IF_DBG(NBT_DEBUG_TDICNCT) KdPrint(("Nbt.NbtTdiAssociateConnection: Failed to build internal device Irp\n")); return(STATUS_UNSUCCESSFUL); } TdiBuildAssociateAddress (pIrp, pFileObject->DeviceObject, pFileObject, NbtTdiCompletionRoutine, &Event, Handle); status = SubmitTdiRequest(pFileObject,pIrp); if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_TDICNCT) KdPrint (("Nbt.NbtTdiAssociateConnection: ERROR -- SubmitTdiRequest returned <%x>\n", status)); } IoFreeIrp(pIrp); return status; } //---------------------------------------------------------------------------- NTSTATUS CreateDeviceString( IN PWSTR AppendingString, IN OUT PUNICODE_STRING pucDeviceName ) /*++ Routine Description: This routine creates a string name for the transport device such as "\Device\Streams\Tcp" Arguments: Return Value: Status of the operation. --*/ { NTSTATUS status; ULONG Len; PVOID pBuffer; PWSTR pTcpBindName = NbtConfig.pTcpBindName; CTEPagedCode(); if (!pTcpBindName) { pTcpBindName = NBT_TCP_BIND_NAME; } // copy device name into the unicode string - either Udp or Tcp // Len = (wcslen(pTcpBindName) + wcslen(AppendingString) + 1) * sizeof(WCHAR); if (pBuffer = NbtAllocMem(Len,NBT_TAG('n'))) { pucDeviceName->MaximumLength = (USHORT)Len; pucDeviceName->Length = 0; pucDeviceName->Buffer = pBuffer; // this puts \Device\Streams into the string // if ((NT_SUCCESS (status = RtlAppendUnicodeToString (pucDeviceName, pTcpBindName))) && (NT_SUCCESS (status = RtlAppendUnicodeToString (pucDeviceName, AppendingString)))) { return(status); } CTEMemFree(pBuffer); } else { status = STATUS_INSUFFICIENT_RESOURCES; } // // Error case -- cleanup! // pucDeviceName->MaximumLength = 0; pucDeviceName->Length = 0; pucDeviceName->Buffer = NULL; return(status); } //---------------------------------------------------------------------------- NTSTATUS NbtTdiCloseConnection( IN tLOWERCONNECTION * pLowerConn ) /*++ Routine Description: This routine closes a TDI connection Arguments: Return Value: Status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; BOOLEAN Attached= FALSE; CTEPagedCode(); ASSERT( pLowerConn != NULL ) ; CTEAttachFsp(&Attached, REF_FSP_CLOSE_CONNECTION); if (pLowerConn->FileHandle) { status = ZwClose(pLowerConn->FileHandle); IF_DBG(NBT_DEBUG_HANDLES) KdPrint (("\t<===<%x>\tNbtTdiCloseConnection->ZwClose, status = <%x>\n", pLowerConn->FileHandle, status)); pLowerConn->FileHandle = NULL; } #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_TDICNCT) KdPrint(("Nbt.NbtTdiCloseConnection: Failed to close LowerConn FileHandle pLower %X, status %X\n", pLowerConn,status)); } #endif CTEDetachFsp(Attached, REF_FSP_CLOSE_CONNECTION); return(status); } //---------------------------------------------------------------------------- NTSTATUS NbtTdiCloseAddress( IN tLOWERCONNECTION * pLowerConn ) /*++ Routine Description: This routine closes a TDI address Arguments: Return Value: Status of the operation. --*/ { NTSTATUS status; BOOLEAN Attached= FALSE; CTEPagedCode(); ASSERT( pLowerConn != NULL ) ; CTEAttachFsp(&Attached, REF_FSP_CLOSE_ADDRESS); status = ZwClose(pLowerConn->AddrFileHandle); IF_DBG(NBT_DEBUG_HANDLES) KdPrint (("\t<===<%x>\tNbtTdiCloseAddress->ZwClose, status = <%x>\n", pLowerConn->AddrFileHandle, status)); #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_TDICNCT) KdPrint(("Nbt.NbtTdiCloseAddress: Failed to close Address FileHandle pLower %X,status %X\n", pLowerConn,status)); } #endif CTEDetachFsp(Attached, REF_FSP_CLOSE_ADDRESS); return(status); }