summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/nt/tdiaddr.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nbt/nt/tdiaddr.c')
-rw-r--r--private/ntos/nbt/nt/tdiaddr.c672
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);
+}
+
+
+