diff options
Diffstat (limited to 'private/ntos/nbt/nt/tdiaddr.c')
-rw-r--r-- | private/ntos/nbt/nt/tdiaddr.c | 672 |
1 files changed, 672 insertions, 0 deletions
diff --git a/private/ntos/nbt/nt/tdiaddr.c b/private/ntos/nbt/nt/tdiaddr.c new file mode 100644 index 000000000..18dbff62f --- /dev/null +++ b/private/ntos/nbt/nt/tdiaddr.c @@ -0,0 +1,672 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + Tdihndlr.c + +Abstract: + + This file contains code relating to manipulation of address objects + that is specific to the NT operating system. It creates address endpoints + with the transport provider. + +Author: + + Jim Stewart (Jimst) 10-2-92 + +Revision History: + +--*/ + +#include "nbtprocs.h" + +//******************* Pageable Routine Declarations **************** +#ifdef ALLOC_PRAGMA +#pragma CTEMakePageable(PAGE, NbtTdiOpenAddress) +#pragma CTEMakePageable(PAGE, NbtTdiOpenControl) +#pragma CTEMakePageable(PAGE, SetEventHandler) +#pragma CTEMakePageable(PAGE, SubmitTdiRequest) +#endif +//******************* Pageable Routine Declarations **************** + +//---------------------------------------------------------------------------- +NTSTATUS +NbtTdiOpenAddress ( + OUT PHANDLE pHandle, + OUT PDEVICE_OBJECT *ppDeviceObject, + OUT PFILE_OBJECT *ppFileObject, + IN tDEVICECONTEXT *pDeviceContext, + IN USHORT PortNumber, + IN ULONG IpAddress, + IN ULONG Flags + ) +/*++ + +Routine Description: + + Note: This synchronous call may take a number of seconds. It runs in + the context of the caller. The code Opens an Address object with the + transport provider and then sets up event handlers for Receive, + Disconnect, Datagrams and Errors. + + THIS ROUTINE MUST BE CALLED IN THE CONTEXT OF THE FSP (I.E. + PROBABLY AN EXECUTIVE WORKER THREAD). + + The address data structures are found in tdi.h , but they are rather + confusing since the definitions have been spread across several data types. + This section shows the complete data type for Ip address: + + typedef struct + { + int TA_AddressCount; + struct _TA_ADDRESS + { + USHORT AddressType; + USHORT AddressLength; + struct _TDI_ADDRESS_IP + { + USHORT sin_port; + USHORT in_addr; + UCHAR sin_zero[8]; + } TDI_ADDRESS_IP + + } TA_ADDRESS[AddressCount]; + + } TRANSPORT_ADDRESS + + An EA buffer is allocated (for the IRP), with an EA name of "TransportAddress" + and value is a structure of type TRANSPORT_ADDRESS. + +Arguments: + + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + + + OBJECT_ATTRIBUTES AddressAttributes; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_FULL_EA_INFORMATION EaBuffer; + NTSTATUS status; + PWSTR pNameTcp=L"Tcp"; + PWSTR pNameUdp=L"Udp"; + UNICODE_STRING ucDeviceName; + PTRANSPORT_ADDRESS pTransAddressEa; + PTRANSPORT_ADDRESS pTransAddr; + TDI_ADDRESS_IP IpAddr; + BOOLEAN Attached = FALSE; + PFILE_OBJECT pFileObject; + HANDLE FileHandle; + + CTEPagedCode(); + *ppFileObject = NULL; + *ppDeviceObject = NULL; + // copy device name into the unicode string - either Udp or Tcp + // + if (Flags & TCP_FLAG) + status = CreateDeviceString(pNameTcp,&ucDeviceName); + else + status = CreateDeviceString(pNameUdp,&ucDeviceName); + + if (!NT_SUCCESS(status)) + { + return(status); + } + EaBuffer = NbtAllocMem( + sizeof(FILE_FULL_EA_INFORMATION) - 1 + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof(TRANSPORT_ADDRESS) + + sizeof(TDI_ADDRESS_IP),NBT_TAG('j')); + + if (EaBuffer == NULL) + { + ASSERTMSG( + (PCHAR)"Unable to get memory for an Eabuffer to open an address", + (PVOID)EaBuffer); + CTEMemFree(ucDeviceName.Buffer); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + EaBuffer->NextEntryOffset = 0; + EaBuffer->Flags = 0; + EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; + + EaBuffer->EaValueLength = sizeof(TRANSPORT_ADDRESS) -1 + + sizeof(TDI_ADDRESS_IP); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("EaValueLength = %d\n",EaBuffer->EaValueLength)); + + // put "TransportAddress" into the name + // + RtlMoveMemory( + EaBuffer->EaName, + TdiTransportAddress, + EaBuffer->EaNameLength + 1); + + // fill in the IP address and Port number + // + pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1]; + + + // allocate Memory for the transport address + // + pTransAddr = NbtAllocMem( + sizeof(TDI_ADDRESS_IP)+sizeof(TRANSPORT_ADDRESS),NBT_TAG('k')); + + pTransAddr->TAAddressCount = 1; + pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); + pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + + IpAddr.sin_port = htons(PortNumber); // put in network order + IpAddr.in_addr = htonl(IpAddress); + + // zero fill the last component of the IP address + // + RtlFillMemory((PVOID)&IpAddr.sin_zero, + sizeof(IpAddr.sin_zero), + 0); + + // copy the ip address to the end of the structure + // + RtlMoveMemory(pTransAddr->Address[0].Address, + (CONST PVOID)&IpAddr, + sizeof(IpAddr)); + + // copy the ip address to the end of the name in the EA structure + // + RtlMoveMemory((PVOID)pTransAddressEa, + (CONST PVOID)pTransAddr, + sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1); + + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("creating Address named %ws\n",ucDeviceName.Buffer)); + + InitializeObjectAttributes( + &AddressAttributes, + &ucDeviceName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = ZwCreateFile( + &FileHandle, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &AddressAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN_IF, + 0, + (PVOID)EaBuffer, + sizeof(FILE_FULL_EA_INFORMATION) - 1 + + EaBuffer->EaNameLength + 1 + + EaBuffer->EaValueLength); + + CTEMemFree((PVOID)pTransAddr); + CTEMemFree((PVOID)EaBuffer); + CTEMemFree(ucDeviceName.Buffer); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("NBT:Failed Create (address) File, status = %X\n",status )); + + if (NT_SUCCESS(status)) + { + // if the ZwCreate passed set the status to the IoStatus + status = IoStatusBlock.Status; + + if (!NT_SUCCESS(status)) + { + KdPrint(("Nbt:Failed to Open the Address to the transport, status = %X\n", + status)); + + return(status); + } + + // dereference the file object to keep the device ptr around to avoid + // this dereference at run time + // + status = ObReferenceObjectByHandle( + FileHandle, + (ULONG)0, + 0, + KernelMode, + (PVOID *)&pFileObject, + NULL); + + if (NT_SUCCESS(status)) + { + // return the handle to the caller + // + *pHandle = FileHandle; + // + // return the parameter to the caller + // + *ppFileObject = pFileObject; + + *ppDeviceObject = IoGetRelatedDeviceObject(*ppFileObject); + + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_ERROR, + (PVOID)TdiErrorHandler, + (PVOID)pDeviceContext); + + if (NT_SUCCESS(status)) + { + // if this is a TCP address being opened, then create different + // event handlers for connections + // + if (Flags & TCP_FLAG) + { + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_RECEIVE, + (PVOID)TdiReceiveHandler, + (PVOID)pDeviceContext); + + if (NT_SUCCESS(status)) + { + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_DISCONNECT, + (PVOID)TdiDisconnectHandler, + (PVOID)pDeviceContext); + + if (NT_SUCCESS(status)) + { + // only set a connect handler if the session flag is set. + // In this case the address being opened is the Netbios session + // port 139 + // + if (Flags & SESSION_FLAG) + { + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_CONNECT, + (PVOID)TdiConnectHandler, + (PVOID)pDeviceContext); + + if (NT_SUCCESS(status)) + { + return(status); + } + + } + else + return(status); + } + } + + + } + else + { + // Datagram ports only need this event handler + if (PortNumber == NBT_DATAGRAM_UDP_PORT) + { + // Datagram Udp Handler + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_RECEIVE_DATAGRAM, + (PVOID)TdiRcvDatagramHandler, + (PVOID)pDeviceContext); + if (NT_SUCCESS(status)) + { + return(status); + } + } + else + { + // Name Service Udp handler + status = SetEventHandler( + *ppDeviceObject, + *ppFileObject, + TDI_EVENT_RECEIVE_DATAGRAM, + (PVOID)TdiRcvNameSrvHandler, + (PVOID)pDeviceContext); + + if (NT_SUCCESS(status)) + { + return(status); + } + } + } + + // + // ERROR Case + // + ObDereferenceObject(pFileObject); + ZwClose(FileHandle); + + return(status); + } + + } + else + { + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("Failed Open Address (Dereference Object) status = %X\n", + status)); + + ZwClose(FileHandle); + } + + } + + + return(status); +} + +//---------------------------------------------------------------------------- +NTSTATUS +NbtTdiOpenControl ( + IN tDEVICECONTEXT *pDeviceContext + ) +/*++ + +Routine Description: + + This routine opens a control object with the transport. It is very similar + to opening an address object, above. + +Arguments: + + + +Return Value: + + Status of the operation. + +--*/ +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + PWSTR pName=L"Tcp"; + PFILE_FULL_EA_INFORMATION EaBuffer; + UNICODE_STRING DeviceName; + BOOLEAN Attached = FALSE; + + + CTEPagedCode(); + // copy device name into the unicode string + Status = CreateDeviceString(pName,&DeviceName); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + InitializeObjectAttributes ( + &ObjectAttributes, + &DeviceName, + 0, + NULL, + NULL); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer)); + + EaBuffer = NULL; + + Status = ZwCreateFile ( + (PHANDLE)&pDeviceContext->hControl, + 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. + 0); // Ea length + + + CTEMemFree(DeviceName.Buffer); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint( ("OpenControl CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status)); + + if ( NT_SUCCESS( Status )) + { + // if the ZwCreate passed set the status to the IoStatus + Status = IoStatusBlock.Status; + + if (!NT_SUCCESS(Status)) + { + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("Nbt:Failed to Open the control connection to the transport, status = %X\n", + Status)); + + } + else + { + // 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( + pDeviceContext->hControl, + 0L, + NULL, + KernelMode, + (PVOID *)&pDeviceContext->pControlFileObject, + NULL); + + if (!NT_SUCCESS(Status)) + { + ZwClose(pDeviceContext->hControl); + } + else + pDeviceContext->pControlDeviceObject = + IoGetRelatedDeviceObject(pDeviceContext->pControlFileObject); + } + + } + else + { + KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n", + Status)); + + // set control file object ptr to null so we know that we didnot open + // the control point. + // + pDeviceContext->pControlFileObject = NULL; + } + + return Status; + +} /* NbtTdiOpenConnection */ + + +//---------------------------------------------------------------------------- +NTSTATUS +CompletionRoutine( + 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 NBT driver that it can proceed (i.e. + to allow some code that is waiting on a "KeWaitForSingleObject" to + proceeed. + +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. + +--*/ +{ + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint( ("Completion event: %X, Irp: %X, DeviceObject: %X\n", + Context, + Irp, + DeviceObject)); + + KeSetEvent((PKEVENT )Context, 0, FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; + + UNREFERENCED_PARAMETER( DeviceObject ); + UNREFERENCED_PARAMETER( Irp ); +} + +//---------------------------------------------------------------------------- +NTSTATUS +SetEventHandler ( + IN PDEVICE_OBJECT DeviceObject, + IN PFILE_OBJECT FileObject, + IN ULONG EventType, + IN PVOID EventHandler, + IN PVOID Context + ) + +/*++ + +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 Context - Supplies the context passed into the event handler when it runs + +Return Value: + + NTSTATUS - Final status of the set event operation + +--*/ + +{ + NTSTATUS Status; + PIRP Irp; + + CTEPagedCode(); + Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE); + + if (Irp == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + TdiBuildSetEventHandler(Irp, DeviceObject, FileObject, + NULL, NULL, + EventType, EventHandler, Context); + + Status = SubmitTdiRequest(FileObject, Irp); + + IoFreeIrp(Irp); + + return Status; +} + +//---------------------------------------------------------------------------- +NTSTATUS +SubmitTdiRequest ( + IN PFILE_OBJECT FileObject, + IN PIRP Irp + ) + +/*++ + +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. + +--*/ + +{ + KEVENT Event; + NTSTATUS Status; + + + CTEPagedCode(); + KeInitializeEvent (&Event, NotificationEvent, FALSE); + + // set the address of the routine to be executed when the IRP + // finishes. This routine signals the event and allows the code + // below to continue (i.e. KeWaitForSingleObject) + // + IoSetCompletionRoutine(Irp, + (PIO_COMPLETION_ROUTINE)CompletionRoutine, + (PVOID)&Event, + TRUE, TRUE, TRUE); + + CHECK_COMPLETION(Irp); + Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); + + // + // If it failed immediately, return now, otherwise wait. + // + + if (!NT_SUCCESS(Status)) + { + KdPrint(("Failed to Submit Tdi Request, status = %X\n",Status)); + return Status; + } + + if (Status == STATUS_PENDING) + { + + Status = KeWaitForSingleObject((PVOID)&Event, // Object to wait on. + Executive, // Reason for waiting + KernelMode, // Processor mode + FALSE, // Alertable + NULL); // Timeout + + if (!NT_SUCCESS(Status)) + { + KdPrint(("Failed on return from KeWaitForSingleObj in Set Event Handler, status = %X\n", + Status)); + return Status; + } + + Status = Irp->IoStatus.Status; + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("Io Status from setting event = %X\n",Status)); + } + + return(Status); +} + + + |