diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/wrapper | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/tdi/wrapper')
-rw-r--r-- | private/ntos/tdi/wrapper/cxport.c | 723 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/makefile | 6 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/sources | 49 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdi.c | 1737 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdi.def | 44 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdi.pnp | 44 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdi.rc | 12 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdidebug.h | 52 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdipnp.c | 1029 | ||||
-rw-r--r-- | private/ntos/tdi/wrapper/tdipnp.h | 163 |
10 files changed, 3859 insertions, 0 deletions
diff --git a/private/ntos/tdi/wrapper/cxport.c b/private/ntos/tdi/wrapper/cxport.c new file mode 100644 index 000000000..db444df32 --- /dev/null +++ b/private/ntos/tdi/wrapper/cxport.c @@ -0,0 +1,723 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + cxport.c + +Abstract: + + Common Transport Environment utility functions for the NT environment + +Author: + + Mike Massa (mikemas) Aug 11, 1993 + +Revision History: + + Who When What + -------- -------- ---------------------------------------------- + mikemas 08-11-93 created + +Notes: + +--*/ + +#include <ntddk.h> +#include <ndis.h> +#include <cxport.h> +#include <tdistat.h> + + +// +// Mark pageable code +// +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, CTELogEvent) + +#endif // ALLOC_PRAGMA + + +// +// Local variables +// +ULONG CTEpTimeIncrement = 0; // used to convert kernel clock ticks to 100ns. + + // Used in the conversion of 100ns times to milliseconds. +static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758}; + + +// +// Macros +// +//++ +// +// LARGE_INTEGER +// CTEConvertMillisecondsTo100ns( +// IN LARGE_INTEGER MsTime +// ); +// +// Routine Description: +// +// Converts time expressed in hundreds of nanoseconds to milliseconds. +// +// Arguments: +// +// MsTime - Time in milliseconds. +// +// Return Value: +// +// Time in hundreds of nanoseconds. +// +//-- + +#define CTEConvertMillisecondsTo100ns(MsTime) \ + RtlExtendedIntegerMultiply(MsTime, 10000) + + +//++ +// +// LARGE_INTEGER +// CTEConvert100nsToMilliseconds( +// IN LARGE_INTEGER HnsTime +// ); +// +// Routine Description: +// +// Converts time expressed in hundreds of nanoseconds to milliseconds. +// +// Arguments: +// +// HnsTime - Time in hundreds of nanoseconds. +// +// Return Value: +// +// Time in milliseconds. +// +//-- + +#define SHIFT10000 13 +extern LARGE_INTEGER Magic10000; + +#define CTEConvert100nsToMilliseconds(HnsTime) \ + RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000) + + +// +// Local functions +// +VOID +CTEpEventHandler( + IN PVOID Context + ) +/*++ + +Routine Description: + + Internal handler for scheduled CTE Events. Conforms to calling convention + for ExWorkerThread handlers. Calls the CTE handler registered for this + event. + +Arguments: + + Context - Work item to process. + +Return Value: + + None. + +--*/ + +{ + CTEEvent *Event; + CTELockHandle Handle; + +#if DBG + KIRQL StartingIrql; + + StartingIrql = KeGetCurrentIrql(); +#endif + + Event = (CTEEvent *) Context; + + CTEGetLock(&(Event->ce_lock), &Handle); + ASSERT(Event->ce_scheduled); + Event->ce_scheduled = 0; + CTEFreeLock(&(Event->ce_lock), Handle); + + (*Event->ce_handler)(Event, Event->ce_arg); + +#if DBG + if (KeGetCurrentIrql() != StartingIrql) { + DbgPrint( + "CTEpEventHandler: routine %lx , event %lx returned at raised IRQL\n", + Event->ce_handler, Event + ); + DbgBreakPoint(); + } +#endif +} + + +VOID +CTEpTimerHandler( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + Internal handler for scheduled CTE Timers. Conforms to calling convention + for NT DPC handlers. Calls the CTE handler registered for this timer. + +Arguments: + + Dpc - Pointer to the DPC routine being run. + DeferredContext - Private context for this instance of the DPC. + SystemArgument1 - Additional argument. + SystemArgument2 - Additional argument. + +Return Value: + + None. + +--*/ + +{ + CTETimer *Timer; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + Timer = (CTETimer *) DeferredContext; + (*Timer->t_handler)((CTEEvent *)Timer, Timer->t_arg); +} + + +// +// Exported functions. +// +int +CTEInitialize( + VOID + ) + +/*++ + +Routine Description: + + Initializes the Common Tranport Environment (CTE). + +Arguments: + + None. + +Return Value: + + 0 if initialization fails. Nonzero otherwise. + +--*/ + +{ + CTEpTimeIncrement = KeQueryTimeIncrement(); + + return(1); +} + + +void +CTEInitEvent( + CTEEvent *Event, + CTEEventRtn Handler + ) +/*++ + +Routine Description: + + Initializes a CTE Event variable. + +Arguments: + + Event - Event variable to initialize. + Handler - Handler routine for this event variable. + +Return Value: + + None. + +--*/ + +{ + ASSERT(Handler != NULL); + + Event->ce_handler = Handler; + Event->ce_scheduled = 0; + CTEInitLock(&(Event->ce_lock)); + ExInitializeWorkItem(&(Event->ce_workitem), CTEpEventHandler, Event); +} + + +int +CTEScheduleEvent( + IN CTEEvent *Event, + IN void *Argument OPTIONAL + ) + +/*++ + +Routine Description: + + Schedules a routine to be executed later in a different context. In the + NT environment, the event is implemented using Executive worker threads. + +Arguments: + + Event - Pointer to a CTE Event variable + Argument - An argument to pass to the event handler when it is called + +Return Value: + + 0 if the event could not be scheduled. Nonzero otherwise. + +--*/ + +{ + CTELockHandle Handle; + + CTEGetLock(&(Event->ce_lock), &Handle); + + if (!(Event->ce_scheduled)) { + Event->ce_scheduled = 1; + Event->ce_arg = Argument; + + ExQueueWorkItem( + &(Event->ce_workitem), + CriticalWorkQueue + ); + } + + CTEFreeLock(&(Event->ce_lock), Handle); + + return(1); +} + + +void +CTEInitTimer( + CTETimer *Timer + ) +/*++ + +Routine Description: + + Initializes a CTE Timer variable. + +Arguments: + + Timer - Timer variable to initialize. + +Return Value: + + None. + +--*/ + +{ + Timer->t_handler = NULL; + Timer->t_arg = NULL; + KeInitializeDpc(&(Timer->t_dpc), CTEpTimerHandler, Timer); + KeInitializeTimer(&(Timer->t_timer)); +} + + +void * +CTEStartTimer( + CTETimer *Timer, + unsigned long DueTime, + CTEEventRtn Handler, + void *Context + ) + +/*++ + +Routine Description: + + Sets a CTE Timer for expiration. + +Arguments: + + Timer - Pointer to a CTE Timer variable. + DueTime - Time in milliseconds after which the timer should expire. + Handler - Timer expiration handler routine. + Context - Argument to pass to the handler. + +Return Value: + + 0 if the timer could not be set. Nonzero otherwise. + +--*/ + +{ + LARGE_INTEGER LargeDueTime; + + ASSERT(Handler != NULL); + + // + // Convert milliseconds to hundreds of nanoseconds and negate to make + // an NT relative timeout. + // + LargeDueTime.HighPart = 0; + LargeDueTime.LowPart = DueTime; + LargeDueTime = CTEConvertMillisecondsTo100ns(LargeDueTime); + LargeDueTime.QuadPart = -LargeDueTime.QuadPart; + + Timer->t_handler = Handler; + Timer->t_arg = Context; + + KeSetTimer( + &(Timer->t_timer), + LargeDueTime, + &(Timer->t_dpc) + ); + + return((void *) 1); +} + + +unsigned long +CTESystemUpTime( + void + ) + +/*++ + +Routine Description: + + Provides the time since system boot in milliseconds. + +Arguments: + + None. + +Return Value: + + The time since boot in milliseconds. + +--*/ + +{ + LARGE_INTEGER TickCount; + + // + // Get tick count and convert to hundreds of nanoseconds. + // + KeQueryTickCount(&TickCount); + + TickCount = RtlExtendedIntegerMultiply( + TickCount, + (LONG) CTEpTimeIncrement + ); + + TickCount = CTEConvert100nsToMilliseconds(TickCount); + + ASSERT(TickCount.HighPart == 0); + + return(TickCount.LowPart); +} + + +extern uint +CTEBlock( + IN CTEBlockStruc *BlockEvent + ) +{ + NTSTATUS Status; + + Status = KeWaitForSingleObject( + &(BlockEvent->cbs_event), + UserRequest, + KernelMode, + FALSE, + NULL + ); + + if (!NT_SUCCESS(Status)) { + // + // BUGBUG: Do something better here. + // + BlockEvent->cbs_status = Status; + } + + return(BlockEvent->cbs_status); +} + + +extern void +CTESignal( + IN CTEBlockStruc *BlockEvent, + IN uint Status + ) +{ + BlockEvent->cbs_status = Status; + KeSetEvent(&(BlockEvent->cbs_event), 0, FALSE); + return; +} + + +BOOLEAN +CTEInitString( + IN OUT PNDIS_STRING DestinationString, + IN char *SourceString + ) + +/*++ + +Routine Description: + + Converts a C style ASCII string to an NDIS_STRING. Resources needed for + the NDIS_STRING are allocated and must be freed by a call to + CTEFreeString. + +Arguments: + + DestinationString - A pointer to an NDIS_STRING variable with no + associated data buffer. + + SourceString - The C style ASCII string source. + + +Return Value: + + TRUE if the initialization succeeded. FALSE otherwise. + +--*/ + +{ + STRING AnsiString; + ULONG UnicodeLength; + + RtlInitString(&AnsiString, SourceString); + + // calculate size of unicoded ansi string + 2 for NULL terminator + UnicodeLength = RtlAnsiStringToUnicodeSize(&AnsiString) + 2; + DestinationString->MaximumLength = (USHORT) UnicodeLength; + + // allocate storage for the unicode string + DestinationString->Buffer = ExAllocatePool(NonPagedPool, UnicodeLength); + + if (DestinationString->Buffer == NULL) { + return(FALSE); + } + + // Finally, convert the string to unicode + RtlAnsiStringToUnicodeString(DestinationString, &AnsiString, FALSE); + + return(TRUE); +} + + +BOOLEAN +CTEAllocateString( + PNDIS_STRING String, + unsigned short MaximumLength + ) + +/*++ + +Routine Description: + + Allocates a data buffer for Length characters in an uninitialized + NDIS_STRING. The allocated space must be freed by a call to CTEFreeString. + + +Arguments: + + String - A pointer to an NDIS_STRING variable with no + associated data buffer. + + Length - The maximum length of the string. In Unicode, this is a + byte count. + +Return Value: + + TRUE if the initialization succeeded. FALSE otherwise. + +--*/ + +{ + String->Buffer = ExAllocatePool( + NonPagedPool, + MaximumLength + sizeof(UNICODE_NULL) + ); + + if (String->Buffer == NULL) { + return(FALSE); + } + + String->Length = 0; + String->MaximumLength = MaximumLength + sizeof(UNICODE_NULL); + + return(TRUE); +} + + + +LONG +CTELogEvent( + IN PVOID LoggerId, + IN ULONG EventCode, + IN ULONG UniqueEventValue, + IN USHORT NumStrings, + IN PVOID StringsList, OPTIONAL + IN ULONG DataSize, + IN PVOID Data OPTIONAL + ) + +/*++ + +Routine Description: + + This function allocates an I/O error log record, fills it in and writes it + to the I/O error log. + + +Arguments: + + LoggerId - Pointer to the driver object logging this event. + + EventCode - Identifies the error message. + + UniqueEventValue - Identifies this instance of a given error message. + + NumStrings - Number of unicode strings in strings list. + + DataSize - Number of bytes of data. + + Strings - Array of pointers to unicode strings (PWCHAR). + + Data - Binary dump data for this message, each piece being + aligned on word boundaries. + +Return Value: + + TDI_SUCCESS - The error was successfully logged. + TDI_BUFFER_TOO_SMALL - The error data was too large to be logged. + TDI_NO_RESOURCES - Unable to allocate memory. + +Notes: + + This code is paged and may not be called at raised IRQL. + +--*/ +{ + PIO_ERROR_LOG_PACKET ErrorLogEntry; + ULONG PaddedDataSize; + ULONG PacketSize; + ULONG TotalStringsSize = 0; + USHORT i; + PWCHAR *Strings; + PWCHAR Tmp; + + + PAGED_CODE(); + + Strings = (PWCHAR *) StringsList; + + // + // Sum up the length of the strings + // + for (i=0; i<NumStrings; i++) { + PWCHAR currentString; + ULONG stringSize; + + stringSize = sizeof(UNICODE_NULL); + currentString = Strings[i]; + + while (*currentString++ != UNICODE_NULL) { + stringSize += sizeof(WCHAR); + } + + TotalStringsSize += stringSize; + } + + if (DataSize % sizeof(ULONG)) { + PaddedDataSize = DataSize + + (sizeof(ULONG) - (DataSize % sizeof(ULONG))); + } + else { + PaddedDataSize = DataSize; + } + + PacketSize = TotalStringsSize + PaddedDataSize; + + if (PacketSize > CTE_MAX_EVENT_LOG_DATA_SIZE) { + return(TDI_BUFFER_TOO_SMALL); // Too much error data + } + + // + // Now add in the size of the log packet, but subtract 4 from the data + // since the packet struct contains a ULONG for data. + // + if (PacketSize > sizeof(ULONG)) { + PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG); + } + else { + PacketSize += sizeof(IO_ERROR_LOG_PACKET); + } + + ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE); + + ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry( + (PDRIVER_OBJECT) LoggerId, + (UCHAR) PacketSize + ); + + if (ErrorLogEntry == NULL) { + return(TDI_NO_RESOURCES); + } + + // + // Fill in the necessary log packet fields. + // + ErrorLogEntry->UniqueErrorValue = UniqueEventValue; + ErrorLogEntry->ErrorCode = EventCode; + ErrorLogEntry->NumberOfStrings = NumStrings; + ErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + + PaddedDataSize - sizeof(ULONG); + ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize; + + // + // Copy the Dump Data to the packet + // + if (DataSize > 0) { + RtlMoveMemory( + (PVOID) ErrorLogEntry->DumpData, + Data, + DataSize + ); + } + + // + // Copy the strings to the packet. + // + Tmp = (PWCHAR) ((char *) ErrorLogEntry + + ErrorLogEntry->StringOffset + + PaddedDataSize); + + for (i=0; i<NumStrings; i++) { + PWCHAR wchPtr = Strings[i]; + + while( (*Tmp++ = *wchPtr++) != UNICODE_NULL); + } + + IoWriteErrorLogEntry(ErrorLogEntry); + + return(TDI_SUCCESS); +} + diff --git a/private/ntos/tdi/wrapper/makefile b/private/ntos/tdi/wrapper/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/tdi/wrapper/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/tdi/wrapper/sources b/private/ntos/tdi/wrapper/sources new file mode 100644 index 000000000..e315b190c --- /dev/null +++ b/private/ntos/tdi/wrapper/sources @@ -0,0 +1,49 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Dave Beaver (dbeaver) 15 June 1991 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=tdi + +TARGETNAME=tdi +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=EXPORT_DRIVER + +INCLUDES=..\..\inc;..\..\..\inc + +C_DEFINES=-DNT + +SOURCES= \ + tdi.c \ + cxport.c \ + tdipnp.c \ + tdi.rc + +DLLDEF=tdi.def + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib + +!IFNDEF 386_WARNING_LEVEL +386_WARNING_LEVEL=/W3 +!ENDIF + diff --git a/private/ntos/tdi/wrapper/tdi.c b/private/ntos/tdi/wrapper/tdi.c new file mode 100644 index 000000000..b2a1805f7 --- /dev/null +++ b/private/ntos/tdi/wrapper/tdi.c @@ -0,0 +1,1737 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + tdi.c + +Abstract: + + This module contains code which assists the process of writing an NT + TDI client. + +Author: + + David Beaver (dbeaver) 15 June 1991 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include <ntos.h> +#include <status.h> +#include <tdikrnl.h> +#include <ndis.h> +#include "tdipnp.h" + +#if DBG + +#include "tdidebug.h" + +ULONG TdiDebug; + +#define IF_TDIDBG(sts) \ + if ((TdiDebug & sts) != 0) + +#define TDI_DEBUG_NAMES 0x00000001 +#define TDI_DEBUG_DISPATCH 0x00000002 +#define TDI_DEBUG_MAP 0x00000004 + +#else + +#define IF_TDIDBG(sts) \ + if (0) +#endif + +ULONG TdiInitializationCount; + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Temporary entry point needed to initialize the TDI wrapper driver. + +Arguments: + + DriverObject - Pointer to the driver object created by the system. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + // + // BUGBUG This should not be needed! + // + + UNREFERENCED_PARAMETER(DriverObject); + + return STATUS_SUCCESS; + +} // DriverEntry + + +NTSTATUS +TdiMapUserRequest( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + This routine maps a user request from the NtDeviceIoControlFile format + to the kernel mode request format. It does this by probing and locking all + buffers of interest, copying parameter sets to the stack pointer as + appropriate, and generally preparing for the kernel IO form. + +Arguments: + + Irp - pointer to the irp containing this request. + +Return Value: + + NTSTATUS - status of operation. STATUS_UNSUCCESSFUL if the request could + not be mapped, STATUS_NOT_IMPLEMENTED if the IOCTL is not recognized + (allowing driver writers to extend the supported IOCTLs if needed), and + STATUS_SUCCESS if the request was mapped successfully. + +--*/ + +{ + + NTSTATUS Status; + + DeviceObject; + + Status = STATUS_INVALID_PARAMETER; + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_TDI_ACCEPT: + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_ACCEPT; + + Status = STATUS_SUCCESS; + break; + + case IOCTL_TDI_ACTION: + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_ACTION; + + Status = STATUS_SUCCESS; + break; + + case IOCTL_TDI_CONNECT: + { + PTDI_REQUEST_CONNECT userRequest; + PTDI_REQUEST_KERNEL_CONNECT request; + PTDI_CONNECTION_INFORMATION connInfo; + PCHAR ptr; + + if (Irp->AssociatedIrp.SystemBuffer) { + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_CONNECT; + + userRequest = + (PTDI_REQUEST_CONNECT)Irp->AssociatedIrp.SystemBuffer; + connInfo = userRequest->RequestConnectionInformation; + ptr = (PCHAR)(connInfo + 1); + connInfo->UserData = ptr; + ptr += connInfo->UserDataLength; + connInfo->Options = ptr; + ptr += connInfo->OptionsLength; + connInfo->RemoteAddress = ptr; + + request = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters; + request->RequestConnectionInformation = connInfo; + + // + // BUGBUG: Fill this in too? + // + + request->ReturnConnectionInformation = NULL; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_DISCONNECT: + { + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_DISCONNECT; + + Status = STATUS_SUCCESS; + break; + } + + case IOCTL_TDI_LISTEN: + { + PTDI_REQUEST_LISTEN userRequest; + PTDI_REQUEST_KERNEL_LISTEN request; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_LISTEN)Irp->AssociatedIrp.SystemBuffer; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_LISTEN; + + request = (PTDI_REQUEST_KERNEL_LISTEN)&IrpSp->Parameters; + request->RequestFlags = userRequest->ListenFlags; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_QUERY_INFORMATION: + { + PTDI_REQUEST_QUERY_INFORMATION userRequest; + PTDI_REQUEST_KERNEL_QUERY_INFORMATION request; + PTDI_CONNECTION_INFORMATION connInfo; + PCHAR ptr; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_QUERY_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_QUERY_INFORMATION; + + request = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters; + request->QueryType = userRequest->QueryType; + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength > + sizeof (TDI_REQUEST_QUERY_INFORMATION)) + { + connInfo = (PTDI_CONNECTION_INFORMATION)(userRequest + 1); + ptr = (PCHAR)(connInfo + 1); + connInfo->UserData = ptr; + ptr += connInfo->UserDataLength; + connInfo->Options = ptr; + ptr += connInfo->OptionsLength; + connInfo->RemoteAddress = ptr; + request->RequestConnectionInformation = connInfo; + } + else + request->RequestConnectionInformation = NULL; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_RECEIVE: + { + PTDI_REQUEST_RECEIVE userRequest; + PTDI_REQUEST_KERNEL_RECEIVE request; + ULONG receiveLength; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_RECEIVE)Irp->AssociatedIrp.SystemBuffer; + receiveLength = + IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_RECEIVE; + + request = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters; + request->ReceiveLength = receiveLength; + request->ReceiveFlags = userRequest->ReceiveFlags; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_RECEIVE_DATAGRAM: + { + PTDI_REQUEST_RECEIVE_DATAGRAM userRequest; + PTDI_REQUEST_KERNEL_RECEIVEDG request; + ULONG receiveLength; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_RECEIVE_DATAGRAM)Irp->AssociatedIrp.SystemBuffer; + receiveLength = + IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM; + + request = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IrpSp->Parameters; + request->ReceiveLength = receiveLength; + request->ReceiveFlags = userRequest->ReceiveFlags; + request->ReceiveDatagramInformation = userRequest->ReceiveDatagramInformation; + request->ReturnDatagramInformation = userRequest->ReturnInformation; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_SEND: + { + PTDI_REQUEST_SEND userRequest; + PTDI_REQUEST_KERNEL_SEND request; + ULONG sendLength; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_SEND)Irp->AssociatedIrp.SystemBuffer; + sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_SEND; + + request = (PTDI_REQUEST_KERNEL_SEND)&IrpSp->Parameters; + request->SendLength = sendLength; + request->SendFlags = userRequest->SendFlags; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_SEND_DATAGRAM: + { + PTDI_REQUEST_SEND_DATAGRAM userRequest; + PTDI_REQUEST_KERNEL_SENDDG request; + ULONG sendLength; + + if (Irp->AssociatedIrp.SystemBuffer) { + + sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_SEND_DATAGRAM; + + request = (PTDI_REQUEST_KERNEL_SENDDG)&IrpSp->Parameters; + request->SendLength = sendLength; + + userRequest = (PTDI_REQUEST_SEND_DATAGRAM)Irp->AssociatedIrp.SystemBuffer; + request->SendDatagramInformation = userRequest->SendDatagramInformation; + Status = STATUS_SUCCESS; + } + break; + } + + case IOCTL_TDI_SET_EVENT_HANDLER: + + // + // Because this request will enable direct callouts from the + // transport provider at DISPATCH_LEVEL to a client-specified + // routine, this request is only valid in kernel mode, denying + // access to this request in user mode. + // + + Status = STATUS_INVALID_PARAMETER; + break; + + case IOCTL_TDI_SET_INFORMATION: + { + PTDI_REQUEST_SET_INFORMATION userRequest; + PTDI_REQUEST_KERNEL_SET_INFORMATION request; + + if (Irp->AssociatedIrp.SystemBuffer) { + + userRequest = + (PTDI_REQUEST_SET_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_SET_INFORMATION; + + request = (PTDI_REQUEST_KERNEL_SET_INFORMATION)&IrpSp->Parameters; + request->SetType = userRequest->SetType; + request->RequestConnectionInformation = NULL; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_ASSOCIATE_ADDRESS: + { + PTDI_REQUEST_ASSOCIATE_ADDRESS userRequest; + PTDI_REQUEST_KERNEL_ASSOCIATE request; + + if (Irp->AssociatedIrp.SystemBuffer) { + + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_ASSOCIATE_ADDRESS; + + userRequest = + (PTDI_REQUEST_ASSOCIATE_ADDRESS)Irp->AssociatedIrp.SystemBuffer; + request = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters; + request->AddressHandle = userRequest->AddressHandle; + + Status = STATUS_SUCCESS; + + } + break; + } + + case IOCTL_TDI_DISASSOCIATE_ADDRESS: + { + IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IrpSp->MinorFunction = TDI_DISASSOCIATE_ADDRESS; + + Status = STATUS_SUCCESS; + break; + } + + default: + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + return Status; + +} + + +NTSTATUS +TdiDefaultConnectHandler( + IN PVOID TdiEventContext, + IN LONG RemoteAddressLength, + IN PVOID RemoteAddress, + IN LONG UserDataLength, + IN PVOID UserData, + IN LONG OptionsLength, + IN PVOID Options, + OUT CONNECTION_CONTEXT *ConnectionContext, + OUT PIRP *AcceptIrp + ) + +/*++ + +Routine Description: + + This routine is called when a connect request has completed. The connection + is fully functional when the indication occurs. + +Arguments: + + TdiEventContext - the context value passed in by the user in the Set Event Handler call + + RemoteAddressLength, + + RemoteAddress, + + UserDataLength, + + UserData, + + OptionsLength, + + Options, + + ConnectionId + +Return Value: + + The function value is the final status from the initialization operation. + +--*/ +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (RemoteAddressLength); + UNREFERENCED_PARAMETER (RemoteAddress); + UNREFERENCED_PARAMETER (UserDataLength); + UNREFERENCED_PARAMETER (UserData); + UNREFERENCED_PARAMETER (OptionsLength); + UNREFERENCED_PARAMETER (Options); + UNREFERENCED_PARAMETER (ConnectionContext); + + return STATUS_INSUFFICIENT_RESOURCES; // do nothing +} + + +NTSTATUS +TdiDefaultDisconnectHandler( + IN PVOID TdiEventContext, + IN CONNECTION_CONTEXT ConnectionContext, + IN LONG DisconnectDataLength, + IN PVOID DisconnectData, + IN LONG DisconnectInformationLength, + IN PVOID DisconnectInformation, + IN ULONG DisconnectFlags + ) + +/*++ + +Routine Description: + + This routine is used as the default disconnect event handler + for the transport endpoint. It is pointed to by a field in the + TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TransportEndpoint - Pointer to open file object. + + Context - Typeless pointer specifying connection context. + + DisconnectIndicators - Value indicating reason for disconnection indication. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (DisconnectDataLength); + UNREFERENCED_PARAMETER (DisconnectData); + UNREFERENCED_PARAMETER (DisconnectInformationLength); + UNREFERENCED_PARAMETER (DisconnectInformation); + UNREFERENCED_PARAMETER (DisconnectFlags); + + return STATUS_SUCCESS; // do nothing but return successfully. + +} /* DefaultDisconnectHandler */ + + +NTSTATUS +TdiDefaultErrorHandler( + IN PVOID TdiEventContext, // the endpoint's file object. + IN NTSTATUS Status // status code indicating error type. + ) + +/*++ + +Routine Description: + + This routine is used as the default error event handler for + the transport endpoint. It is pointed to by a field in the + TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TransportEndpoint - Pointer to open file object. + + Status - Status code indicated by this event. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (Status); + + return STATUS_SUCCESS; // do nothing but return successfully. + +} /* DefaultErrorHandler */ + + +NTSTATUS +TdiDefaultReceiveHandler( + IN PVOID TdiEventContext, + IN CONNECTION_CONTEXT ConnectionContext, + IN ULONG ReceiveFlags, + IN ULONG BytesIndicated, + IN ULONG BytesAvailable, + OUT ULONG *BytesTaken, + IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes + OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED. + ) + +/*++ + +Routine Description: + + This routine is used as the default receive event handler for + the transport endpoint. It is pointed to by a field in the + TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_RECEIVE. + + ConnectionContext - The client-supplied context associated with + the connection on which this connection-oriented TSDU was received. + + ReceiveFlags - Bitflags which indicate the circumstances surrounding + this TSDU's reception. + + BytesIndicated - The number of bytes of this TSDU that are being presented + to the client in this indication.This value is always less than + or equal to BytesAvailable. + + BytesAvailable - The total number of bytes of this TSDU presently + available from the transport. + + BytesTaken - Return value indicating the number of bytes of data that the + client copied from the indication data. + + Tsdu - Pointer to an MDL chain that describes the (first) part of the + (partially) received Transport Service Data Unit, less headers. + + IoRequestPacket - Pointer to a location where the event handler may + chose to return a pointer to an I/O Request Packet (IRP) to satisfy + the incoming data. If returned, this IRP must be formatted as a + valid TdiReceive request, except that the ConnectionId field of + the TdiRequest is ignored and is automatically filled in by the + transport provider. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (ReceiveFlags); + UNREFERENCED_PARAMETER (BytesIndicated); + UNREFERENCED_PARAMETER (BytesAvailable); + UNREFERENCED_PARAMETER (BytesTaken); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (IoRequestPacket); + + return STATUS_DATA_NOT_ACCEPTED; // no handler in place. + +} /* DefaultReceiveHandler */ + + +NTSTATUS +TdiDefaultRcvDatagramHandler( + IN PVOID TdiEventContext, // the event context + IN LONG SourceAddressLength, // length of the originator of the datagram + IN PVOID SourceAddress, // string describing the originator of the datagram + IN LONG OptionsLength, // options for the receive + IN PVOID Options, // + IN ULONG ReceiveDatagramFlags, // + IN ULONG BytesIndicated, // number of bytes this indication + IN ULONG BytesAvailable, // number of bytes in complete Tsdu + OUT ULONG *BytesTaken, // number of bytes used + IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes + OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED. + ) + +/*++ + +Routine Description: + + This routine is used as the default receive datagram event + handler for the transport endpoint. It is pointed to by a + field in the TP_ENDPOINT structure for an endpoint when the + endpoint is created, and also whenever the TdiSetEventHandler + request is submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_RECEIVE_DATAGRAM. + + DestinationAddress - Pointer to the network name of the destination + to which the datagram was directed. + + SourceAddress - Pointer to the network name of the source from which + the datagram originated. + + Tsap - Transport service access point on which this datagram was received. + + ReceiveIndicators - Bitflags which indicate the circumstances surrounding + this TSDU's reception. + + Tsdu - Pointer to an MDL chain that describes the (first) part of the + (partially) received Transport Service Data Unit, less headers. + + IoRequestPacket - Pointer to a location where the event handler may + chose to return a pointer to an I/O Request Packet (IRP) to satisfy + the incoming data. If returned, this IRP must be formatted as a + valid TdiReceiveDatagram request. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (SourceAddressLength); + UNREFERENCED_PARAMETER (SourceAddress); + UNREFERENCED_PARAMETER (OptionsLength); + UNREFERENCED_PARAMETER (Options); + UNREFERENCED_PARAMETER (BytesIndicated); + UNREFERENCED_PARAMETER (BytesAvailable); + UNREFERENCED_PARAMETER (BytesTaken); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (IoRequestPacket); + + return STATUS_DATA_NOT_ACCEPTED; // no handler in place. + +} /* DefaultRcvDatagramHandler */ + + +NTSTATUS +TdiDefaultRcvExpeditedHandler( + IN PVOID TdiEventContext, + IN CONNECTION_CONTEXT ConnectionContext, + IN ULONG ReceiveFlags, // + IN ULONG BytesIndicated, // number of bytes in this indication + IN ULONG BytesAvailable, // number of bytes in complete Tsdu + OUT ULONG *BytesTaken, // number of bytes used by indication routine + IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes + OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED. + ) + +/*++ + +Routine Description: + + This routine is used as the default expedited receive event handler + for the transport endpoint. It is pointed to by a field in the + TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_RECEIVE. + + ConnectionContext - The client-supplied context associated with + the connection on which this connection-oriented TSDU was received. + + ReceiveFlags - Bitflags which indicate the circumstances surrounding + this TSDU's reception. + + BytesIndicated - The number of bytes of this TSDU that are being presented + to the client in this indication.This value is always less than + or equal to BytesAvailable. + + BytesAvailable - The total number of bytes of this TSDU presently + available from the transport. + + BytesTaken - Return value indicating the number of bytes of data that the + client copied from the indication data. + + Tsdu - Pointer to an MDL chain that describes the (first) part of the + (partially) received Transport Service Data Unit, less headers. + + IoRequestPacket - Pointer to a location where the event handler may + chose to return a pointer to an I/O Request Packet (IRP) to satisfy + the incoming data. If returned, this IRP must be formatted as a + valid TdiReceive request, except that the ConnectionId field of + the TdiRequest is ignored and is automatically filled in by the + transport provider. + +Return Value: + + NTSTATUS - status of operation. + +--*/ +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (ReceiveFlags); + UNREFERENCED_PARAMETER (BytesIndicated); + UNREFERENCED_PARAMETER (BytesAvailable); + UNREFERENCED_PARAMETER (BytesTaken); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (IoRequestPacket); + + return STATUS_DATA_NOT_ACCEPTED; + +} /* DefaultRcvExpeditedHandler */ + +NTSTATUS +TdiDefaultChainedReceiveHandler ( + IN PVOID TdiEventContext, + IN CONNECTION_CONTEXT ConnectionContext, + IN ULONG ReceiveFlags, + IN ULONG ReceiveLength, + IN ULONG StartingOffset, + IN PMDL Tsdu, + IN PVOID TsduDescriptor + ) + +/*++ + +Routine Description: + + This routine is used as the default chanied receive event handler + for the transport endpoint. It is pointed to by a field in the + TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE. + + ConnectionContext - The client-supplied context associated with + the connection on which this connection-oriented TSDU was received. + + ReceiveFlags - Bitflags which indicate the circumstances surrounding + this TSDU's reception. + + ReceiveLength - The length in bytes of client data in the TSDU. + + StartingOffset - The offset, in bytes from the beginning of the TSDU, + at which the client data begins. + + Tsdu - Pointer to an MDL chain that describes the entire received + Transport Service Data Unit. + + TsduDescriptor - A descriptor for the TSDU which must be passed to + TdiReturnChainedReceives in order to return the TSDU for reuse. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (ReceiveFlags); + UNREFERENCED_PARAMETER (ReceiveLength); + UNREFERENCED_PARAMETER (StartingOffset); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (TsduDescriptor); + + return STATUS_DATA_NOT_ACCEPTED; + +} /* DefaultChainedReceiveHandler */ + + +NTSTATUS +TdiDefaultChainedRcvDatagramHandler( + IN PVOID TdiEventContext, + IN LONG SourceAddressLength, + IN PVOID SourceAddress, + IN LONG OptionsLength, + IN PVOID Options, + IN ULONG ReceiveDatagramFlags, + IN ULONG ReceiveDatagramLength, + IN ULONG StartingOffset, + IN PMDL Tsdu, + IN PVOID TsduDescriptor + ) + +/*++ + +Routine Description: + + This routine is used as the default chained receive datagram + event handler for the transport endpoint. It is pointed to by + a field in the TP_ENDPOINT structure for an endpoint when the + endpoint is created, and also whenever the TdiSetEventHandler + request is submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_DATAGRAM. + + SourceAddressLength - The length of the source network address. + + SourceAddress - Pointer to the network address of the source from which + the datagram originated. + + OptionsLength - The length of the transport options accompanying this TSDU. + + Options - Pointer to the transport options accompanying this TSDU. + + ReceiveDatagramFlags - Bitflags which indicate the circumstances + surrounding this TSDU's reception. + + ReceiveDatagramLength - The length, in bytes, of the client data in + this TSDU. + + StartingOffset - The offset, in bytes from the start of the TSDU, at + which the client data begins. + + Tsdu - Pointer to an MDL chain that describes the received Transport + Service Data Unit. + + TsduDescriptor - A descriptor for the TSDU which must be passed to + TdiReturnChainedReceives in order to return the TSDU for reuse. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (SourceAddressLength); + UNREFERENCED_PARAMETER (SourceAddress); + UNREFERENCED_PARAMETER (OptionsLength); + UNREFERENCED_PARAMETER (Options); + UNREFERENCED_PARAMETER (ReceiveDatagramLength); + UNREFERENCED_PARAMETER (StartingOffset); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (TsduDescriptor); + + return STATUS_DATA_NOT_ACCEPTED; + +} /* DefaultChainedRcvDatagramHandler */ + + +NTSTATUS +TdiDefaultChainedRcvExpeditedHandler( + IN PVOID TdiEventContext, + IN CONNECTION_CONTEXT ConnectionContext, + IN ULONG ReceiveFlags, + IN ULONG ReceiveLength, + IN ULONG StartingOffset, + IN PMDL Tsdu, + IN PVOID TsduDescriptor + ) + +/*++ + +Routine Description: + + This routine is used as the default chained expedited receive event + handler for the transport endpoint. It is pointed to by a field + in the TP_ENDPOINT structure for an endpoint when the endpoint is + created, and also whenever the TdiSetEventHandler request is + submitted with a NULL EventHandler field. + +Arguments: + + TdiEventContext - Pointer to the client-provided context value specified + in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_EXPEDITED. + + ConnectionContext - The client-supplied context associated with + the connection on which this connection-oriented TSDU was received. + + ReceiveFlags - Bitflags which indicate the circumstances surrounding + this TSDU's reception. + + ReceiveLength - The length in bytes of client data in the TSDU. + + StartingOffset - The offset, in bytes from the beginning of the TSDU, + at which the client data begins. + + Tsdu - Pointer to an MDL chain that describes the entire received + Transport Service Data Unit. + + TsduDescriptor - A descriptor for the TSDU which must be passed to + TdiReturnChainedReceives in order to return the TSDU for reuse. + +Return Value: + + NTSTATUS - status of operation. + +--*/ +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (ReceiveFlags); + UNREFERENCED_PARAMETER (ReceiveLength); + UNREFERENCED_PARAMETER (StartingOffset); + UNREFERENCED_PARAMETER (Tsdu); + UNREFERENCED_PARAMETER (TsduDescriptor); + + return STATUS_DATA_NOT_ACCEPTED; + +} /* DefaultRcvExpeditedHandler */ + + +NTSTATUS +TdiDefaultSendPossibleHandler ( + IN PVOID TdiEventContext, + IN PVOID ConnectionContext, + IN ULONG BytesAvailable) + +/*++ + +Routine Description: + +Arguments: + + TdiEventContext - the context value passed in by the user in the Set Event Handler call + + ConnectionContext - connection context of connection which can be sent on + + BytesAvailable - number of bytes which can now be sent + +Return Value: + + ignored by the transport + +--*/ + +{ + UNREFERENCED_PARAMETER (TdiEventContext); + UNREFERENCED_PARAMETER (ConnectionContext); + UNREFERENCED_PARAMETER (BytesAvailable); + + return STATUS_SUCCESS; +} + +VOID +TdiBuildNetbiosAddress( + IN PUCHAR NetbiosName, + IN BOOLEAN IsGroupName, + IN OUT PTA_NETBIOS_ADDRESS NetworkName + ) + +/*++ + +Routine Description: + + This routine builds a TA_NETBIOS_ADDRESS structure in the locations pointed + to by NetworkName. All fields are filled out. + +Arguments: + + NetbiosName - Pointer to a 16-byte buffer where the a netbios name is + supplied. + + IsGroupName - TRUE if this name is a group name, false otherwise. + + NetworkName - A pointer to a TA_NETBIOS_ADDRESS structure that is to + receive the buid TDI address. + +Return Value: + + none. + +--*/ + +{ + IF_TDIDBG (TDI_DEBUG_NAMES) { + DbgPrint ("TdiBuildNetBIOSAddress: Entered.\n"); + } + + NetworkName->TAAddressCount = 1; + NetworkName->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS; + NetworkName->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS); + + if (IsGroupName) { + NetworkName->Address[0].Address[0].NetbiosNameType = + TDI_ADDRESS_NETBIOS_TYPE_GROUP; + } else { + NetworkName->Address[0].Address[0].NetbiosNameType = + TDI_ADDRESS_NETBIOS_TYPE_UNIQUE; + } + + RtlCopyMemory ( + NetworkName->Address[0].Address[0].NetbiosName, + NetbiosName, + 16); + +} /* TdiBuildNetbiosAddress */ + + +NTSTATUS +TdiBuildNetbiosAddressEa ( + IN PUCHAR Buffer, + IN BOOLEAN IsGroupName, + IN PUCHAR NetbiosName + ) + +/*++ + +Routine Description: + + Builds an EA describing a Netbios address in the buffer supplied by the + user. + +Arguments: + + Buffer - pointer to a buffer that the ea is to be built in. This buffer + must be at least 40 bytes long. + + IsGroupName - true if the netbios name is a group name, false otherwise. + + NetbiosName - the netbios name to be inserted in the EA to be built. + +Return Value: + + An informative error code if something goes wrong. STATUS_SUCCESS if the + ea is built properly. + +--*/ + +{ + PFILE_FULL_EA_INFORMATION EaBuffer; + PTA_NETBIOS_ADDRESS TAAddress; + ULONG Length; + + IF_TDIDBG (TDI_DEBUG_NAMES) { + DbgPrint ("TdiBuildNetbiosAddressEa: Entered\n "); + } + + try { + Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof (TA_NETBIOS_ADDRESS); + EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer; + + if (EaBuffer == NULL) { + return STATUS_UNSUCCESSFUL; + } + + EaBuffer->NextEntryOffset = 0; + EaBuffer->Flags = 0; + EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; + EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS); + + RtlCopyMemory ( + EaBuffer->EaName, + TdiTransportAddress, + EaBuffer->EaNameLength + 1); + + TAAddress = (PTA_NETBIOS_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1]; + + TdiBuildNetbiosAddress ( + NetbiosName, + IsGroupName, + TAAddress); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + // + // Couldn't touch the passed parameters; just return an error + // status. + // + + return GetExceptionCode(); + } + + return STATUS_SUCCESS; + +} /* TdiBuildNetbiosAddressEa */ + + +VOID +TdiMapBuffer( + IN PMDL MdlChain + ) + +/*++ + +Routine Description: + + This routine ensures that the MappedSystemVa field of every MDL in an + MDL chain is valid; calling MmMapLockedPages where necessary. + + !!! This routine no longer does anything, and should be removed! + +Arguments: + + MdlChain - Pointer to a chain of MDLs describing the data to be mapped. + +Return Value: + + none. + +--*/ + +{ + MdlChain; + + return; + +} /* TdiMapBuffer */ + + +VOID +TdiUnmapBuffer( + IN PMDL MdlChain + ) + +/*++ + +Routine Description: + + This routine restores the mapped status of every MDL in an MDL chain + where the MappedSystemVa field is equal to StartVa+ByteOffset. + + !!! This routine no longer does anything, and should be removed! + +Arguments: + + MdlChain - Pointer to a chain of MDLs describing the data to be unmapped. + +Return Value: + + none. + +--*/ + +{ + MdlChain; + + return; + +} /* TdiUnmapBuffer */ + + +NTSTATUS +TdiCopyMdlToBuffer( + IN PMDL SourceMdlChain, + IN ULONG SourceOffset, + IN PVOID DestinationBuffer, + IN ULONG DestinationOffset, + IN ULONG DestinationBufferSize, + OUT PULONG BytesCopied + ) + +/*++ + +Routine Description: + + This routine copies data described by the source MDL chain starting at + the source offset, into a flat buffer specified by the SVA starting at + the destination offset. A maximum of DestinationBufferSize bytes can + be copied. The actual number of bytes copied is returned in BytesCopied. + +Arguments: + + SourceMdlChain - Pointer to a chain of MDLs describing the source data. + + SourceOffset - Number of bytes to skip in the source data. + + DestinationBuffer - Pointer to a flat buffer to copy the data to. + + DestinationOffset - Number of leading bytes to skip in the destination buffer. + + DestinationBufferSize - Size of the output buffer, including the offset. + + BytesCopied - Pointer to a longword where the actual number of bytes + transferred will be returned. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + PUCHAR Dest, Src; + ULONG SrcBytesLeft, DestBytesLeft, BytesSkipped=0; + + IF_TDIDBG (TDI_DEBUG_MAP) { + DbgPrint ("TdiCopyMdlToBuffer: Entered.\n"); + } + + ASSERT( DestinationBufferSize >= DestinationOffset ); + + *BytesCopied = 0; + + // + // Skip source bytes. + // + + Src = MmGetSystemAddressForMdl (SourceMdlChain); + SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain); + while (BytesSkipped < SourceOffset) { + if (SrcBytesLeft > (SourceOffset - BytesSkipped)) { + // PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n"); + SrcBytesLeft -= (SourceOffset - BytesSkipped); + Src += (SourceOffset - BytesSkipped); + BytesSkipped = SourceOffset; + break; + } else if (SrcBytesLeft == (SourceOffset - BytesSkipped)) { + // PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n"); + SourceMdlChain = SourceMdlChain->Next; + if (SourceMdlChain == NULL) { + //PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n"); + return STATUS_SUCCESS; // no bytes copied. + } + BytesSkipped = SourceOffset; + Src = MmGetSystemAddressForMdl (SourceMdlChain); + SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain); + break; + } else { + // PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n"); + BytesSkipped += SrcBytesLeft; + SourceMdlChain = SourceMdlChain->Next; + if (SourceMdlChain == NULL) { + //PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n"); + return STATUS_SUCCESS; // no bytes copied. + } + Src = MmGetSystemAddressForMdl (SourceMdlChain); + SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain); + } + } + + // PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n"); + + // + // Skip destination bytes. + // + + Dest = (PUCHAR)DestinationBuffer + DestinationOffset; + DestBytesLeft = DestinationBufferSize - DestinationOffset; + + // + // Copy source data into the destination buffer until it's full or + // we run out of data, whichever comes first. + // + + while (DestBytesLeft && SourceMdlChain) { + if (SrcBytesLeft == 0) { + // PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n"); + SourceMdlChain = SourceMdlChain->Next; + if (SourceMdlChain == NULL) { + // PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n"); + return STATUS_SUCCESS; + } + Src = MmGetSystemAddressForMdl (SourceMdlChain); + SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain); + continue; // skip 0-length MDL's. + } + // PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n"); + if (DestBytesLeft == SrcBytesLeft) { + // PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n"); + RtlCopyBytes (Dest, Src, DestBytesLeft); + *BytesCopied += DestBytesLeft; + return STATUS_SUCCESS; + } else if (DestBytesLeft < SrcBytesLeft) { + // PANIC ("TdiCopyMdlToBuffer: Buffer overflow, copying some.\n"); + RtlCopyBytes (Dest, Src, DestBytesLeft); + *BytesCopied += DestBytesLeft; + return STATUS_BUFFER_OVERFLOW; + } else { + // PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n"); + RtlCopyBytes (Dest, Src, SrcBytesLeft); + *BytesCopied += SrcBytesLeft; + DestBytesLeft -= SrcBytesLeft; + Dest += SrcBytesLeft; + SrcBytesLeft = 0; + } + } + + return SourceMdlChain == NULL ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW; +} /* TdiCopyMdlToBuffer */ + + +NTSTATUS +TdiCopyBufferToMdl ( + IN PVOID SourceBuffer, + IN ULONG SourceOffset, + IN ULONG SourceBytesToCopy, + IN PMDL DestinationMdlChain, + IN ULONG DestinationOffset, + IN PULONG BytesCopied + ) + +/*++ + +Routine Description: + + This routine copies data described by the source buffer to the MDL chain + described by the DestinationMdlChain. The + +Arguments: + + SourceBuffer - pointer to the source buffer + + SourceOffset - Number of bytes to skip in the source data. + + SourceBytesToCopy - number of bytes to copy from the source buffer + + DestinationMdlChain - Pointer to a chain of MDLs describing the + destination buffers. + + DestinationOffset - Number of bytes to skip in the destination data. + + BytesCopied - Pointer to a longword where the actual number of bytes + transferred will be returned. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + PUCHAR Dest, Src; + ULONG DestBytesLeft, BytesSkipped=0; + + IF_TDIDBG (TDI_DEBUG_MAP) { + DbgPrint ("TdiCopyBufferToMdl: Entered.\n"); + } + + *BytesCopied = 0; + + // + // Skip Destination bytes. + // + + Dest = MmGetSystemAddressForMdl (DestinationMdlChain); + DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain); + while (BytesSkipped < DestinationOffset) { + if (DestBytesLeft > (DestinationOffset - BytesSkipped)) { + // PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n"); + DestBytesLeft -= (DestinationOffset - BytesSkipped); + Dest += (DestinationOffset - BytesSkipped); + BytesSkipped = DestinationOffset; + break; + } else if (DestBytesLeft == (DestinationOffset - BytesSkipped)) { + // PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n"); + DestinationMdlChain = DestinationMdlChain->Next; + if (DestinationMdlChain == NULL) { + //PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n"); + return STATUS_BUFFER_OVERFLOW; // no bytes copied. + } + BytesSkipped = DestinationOffset; + Dest = MmGetSystemAddressForMdl (DestinationMdlChain); + DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain); + break; + } else { + // PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n"); + BytesSkipped += DestBytesLeft; + DestinationMdlChain = DestinationMdlChain->Next; + if (DestinationMdlChain == NULL) { + //PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n"); + return STATUS_BUFFER_OVERFLOW; // no bytes copied. + } + Dest = MmGetSystemAddressForMdl (DestinationMdlChain); + DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain); + } + } + + // PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n"); + + // + // Skip source bytes. + // + + Src = (PUCHAR)SourceBuffer + SourceOffset; + + // + // Copy source data into the destination buffer until it's full or + // we run out of data, whichever comes first. + // + + while ((SourceBytesToCopy != 0) && (DestinationMdlChain != NULL)) { + if (DestBytesLeft == 0) { + // PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n"); + DestinationMdlChain = DestinationMdlChain->Next; + if (DestinationMdlChain == NULL) { + // PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n"); + return STATUS_BUFFER_OVERFLOW; + } + Dest = MmGetSystemAddressForMdl (DestinationMdlChain); + DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain); + continue; // skip 0-length MDL's. + } + + // PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n"); + if (DestBytesLeft >= SourceBytesToCopy) { + // PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n"); + RtlCopyBytes (Dest, Src, SourceBytesToCopy); + *BytesCopied += SourceBytesToCopy; + return STATUS_SUCCESS; + } else { + // PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n"); + RtlCopyBytes (Dest, Src, DestBytesLeft); + *BytesCopied += DestBytesLeft; + SourceBytesToCopy -= DestBytesLeft; + Src += DestBytesLeft; + DestBytesLeft = 0; + } + } + + return SourceBytesToCopy == 0 ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW; + +} /* TdiCopyBufferToMdl */ + + +NTSTATUS +TdiOpenNetbiosAddress ( + IN OUT PHANDLE FileHandle, + IN PUCHAR Buffer, + IN PVOID DeviceName, + IN PVOID Address) + +/*++ + +Routine Description: + + Opens an address on the given file handle and device. + +Arguments: + + FileHandle - the returned handle to the file object that is opened. + + Buffer - pointer to a buffer that the ea is to be built in. This buffer + must be at least 40 bytes long. + + DeviceName - the Unicode string that points to the device object. + + Name - the address to be registered. If this pointer is NULL, the routine + will attempt to open a "control channel" to the device; that is, it + will attempt to open the file object with a null ea pointer, and if the + transport provider allows for that, will return that handle. + +Return Value: + + An informative error code if something goes wrong. STATUS_SUCCESS if the + returned file handle is valid. + +--*/ +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + PFILE_FULL_EA_INFORMATION EaBuffer; + TA_NETBIOS_ADDRESS NetbiosAddress; + PSZ Name; + ULONG Length; + + IF_TDIDBG (TDI_DEBUG_NAMES) { + DbgPrint ("TdiOpenNetbiosAddress: Opening "); + if (Address == NULL) { + DbgPrint (" Control Channel"); + } else { + DbgPrint (Address); + } + DbgPrint (".\n"); + } + + if (Address != NULL) { + Name = (PSZ)Address; + try { + Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) + + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + + sizeof(TA_NETBIOS_ADDRESS); + EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer; + + if (EaBuffer == NULL) { + return STATUS_UNSUCCESSFUL; + } + + EaBuffer->NextEntryOffset = 0; + EaBuffer->Flags = 0; + EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; + EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS); + + RtlCopyMemory( + EaBuffer->EaName, + TdiTransportAddress, + EaBuffer->EaNameLength + 1 + ); + + // + // Create a copy of the NETBIOS address descriptor in a local + // first, in order to avoid alignment problems. + // + + NetbiosAddress.TAAddressCount = 1; + NetbiosAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS; + NetbiosAddress.Address[0].AddressLength = + sizeof (TDI_ADDRESS_NETBIOS); + NetbiosAddress.Address[0].Address[0].NetbiosNameType = + TDI_ADDRESS_NETBIOS_TYPE_UNIQUE; + RtlCopyMemory( + NetbiosAddress.Address[0].Address[0].NetbiosName, + Name, + 16 + ); + + RtlCopyMemory ( + &EaBuffer->EaName[EaBuffer->EaNameLength + 1], + &NetbiosAddress, + sizeof(TA_NETBIOS_ADDRESS) + ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + // + // Couldn't touch the passed parameters; just return an error + // status. + // + + return GetExceptionCode(); + } + } else { + EaBuffer = NULL; + Length = 0; + } + + InitializeObjectAttributes ( + &ObjectAttributes, + DeviceName, + 0, + NULL, + NULL); + + Status = NtCreateFile ( + FileHandle, + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access. + &ObjectAttributes, // object attributes. + &IoStatusBlock, // returned status information. + 0, // block size (unused). + 0, // file attributes. + FILE_SHARE_READ | FILE_SHARE_WRITE, // share access. + FILE_CREATE, // create disposition. + 0, // create options. + EaBuffer, // EA buffer. + Length); // EA length. + + if (!NT_SUCCESS( Status )) { + IF_TDIDBG (TDI_DEBUG_NAMES) { + DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, NtCreateFile returned status %lx.\n", Status); + } + return Status; + } + + Status = IoStatusBlock.Status; + + if (!(NT_SUCCESS( Status ))) { + IF_TDIDBG (TDI_DEBUG_NAMES) { + DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, IoStatusBlock.Status contains status code=%lx.\n", Status); + } + } + + return Status; +} /* TdiOpenNetbiosAddress */ + + + +VOID +TdiReturnChainedReceives( + IN PVOID *TsduDescriptors, + IN ULONG NumberOfTsdus + ) + +/*++ + +Routine Description: + + Used by a TDI client to return ownership of a set of chained receive TSDUs + to the NDIS layer. This routine may only be called if the client took + ownership of the TSDUs by returning STATUS_PENDING to one of the + CHAINED_RECEIVE indications. + +Arguments: + + TsduDescriptors - An array of TSDU descriptors. Each descriptor was + provided in one of the CHAINED_RECEIVE indications. The descriptors + are actually pointers to the NDIS_PACKETS containing the TSDUs. + + NumberOfTsdus - The count of TSDU descriptors in the TsduDescriptors array. + +Return Value: + + None. +--*/ + +{ + NdisReturnPackets( + (PNDIS_PACKET *) TsduDescriptors, + (UINT) NumberOfTsdus + ); +} + +VOID +TdiInitialize( + VOID + ) + +/*++ + +Routine Description: + + The TDI initialization routine, since our DriverEntry isn't called. + If we're not already initialized we'll initialize our lists heads. + +Arguments: + + Nothing. + +Return Value: + + None. + +--*/ + +{ + // See if we're already initialized. If we're not, + // we won't have an initalized spinlock so we can't use that + // to serialize this. Instead, we interlocked increment a counter + // that is initially 0. If the counter goes to 1, we're the + // first one through here, so we'll do the initialization. Otherwise + // it's already been done, so we'll decrement the counter back + // to it's original state. + + if (InterlockedIncrement(&TdiInitializationCount) == 1) { + + // We're the first ones. + // Initialize the variables the register/deregister code uses. + + KeInitializeSpinLock(&TDIListLock); + + InitializeListHead(&BindClientList); + + InitializeListHead(&NetAddressClientList); + + InitializeListHead(&BindProviderList); + + InitializeListHead(&NetAddressProviderList); + + InitializeListHead(&BindRequestList); + + InitializeListHead(&NetAddressRequestList); + + NdisRegisterTdiCallBack(TdiRegisterDeviceObject); + + } else { + + // Already been done, just decrement the counter. + InterlockedDecrement(&TdiInitializationCount); + } +} + diff --git a/private/ntos/tdi/wrapper/tdi.def b/private/ntos/tdi/wrapper/tdi.def new file mode 100644 index 000000000..17886834f --- /dev/null +++ b/private/ntos/tdi/wrapper/tdi.def @@ -0,0 +1,44 @@ +NAME TDI.SYS + +DESCRIPTION 'TDI.SYS' + +EXPORTS + TdiBuildNetbiosAddress + TdiBuildNetbiosAddressEa + TdiCopyBufferToMdl + TdiCopyMdlToBuffer + TdiDefaultConnectHandler + TdiDefaultDisconnectHandler + TdiDefaultErrorHandler + TdiDefaultRcvDatagramHandler + TdiDefaultRcvExpeditedHandler + TdiDefaultReceiveHandler + TdiMapBuffer + TdiMapUserRequest + TdiOpenNetbiosAddress + TdiUnmapBuffer + TdiDefaultSendPossibleHandler + CTEInitialize + CTEInitEvent + CTEScheduleEvent + CTEInitTimer + CTEStartTimer + CTESystemUpTime + CTEBlock + CTESignal + CTEInitString + CTEAllocateString + CTELogEvent + TdiDefaultChainedRcvDatagramHandler + TdiDefaultChainedRcvExpeditedHandler + TdiDefaultChainedReceiveHandler + TdiReturnChainedReceives + TdiRegisterNotificationHandler + TdiDeregisterNotificationHandler + TdiRegisterDeviceObject + TdiDeregisterDeviceObject + TdiRegisterAddressChangeHandler + TdiDeregisterAddressChangeHandler + TdiRegisterNetAddress + TdiDeregisterNetAddress + TdiInitialize diff --git a/private/ntos/tdi/wrapper/tdi.pnp b/private/ntos/tdi/wrapper/tdi.pnp new file mode 100644 index 000000000..17886834f --- /dev/null +++ b/private/ntos/tdi/wrapper/tdi.pnp @@ -0,0 +1,44 @@ +NAME TDI.SYS + +DESCRIPTION 'TDI.SYS' + +EXPORTS + TdiBuildNetbiosAddress + TdiBuildNetbiosAddressEa + TdiCopyBufferToMdl + TdiCopyMdlToBuffer + TdiDefaultConnectHandler + TdiDefaultDisconnectHandler + TdiDefaultErrorHandler + TdiDefaultRcvDatagramHandler + TdiDefaultRcvExpeditedHandler + TdiDefaultReceiveHandler + TdiMapBuffer + TdiMapUserRequest + TdiOpenNetbiosAddress + TdiUnmapBuffer + TdiDefaultSendPossibleHandler + CTEInitialize + CTEInitEvent + CTEScheduleEvent + CTEInitTimer + CTEStartTimer + CTESystemUpTime + CTEBlock + CTESignal + CTEInitString + CTEAllocateString + CTELogEvent + TdiDefaultChainedRcvDatagramHandler + TdiDefaultChainedRcvExpeditedHandler + TdiDefaultChainedReceiveHandler + TdiReturnChainedReceives + TdiRegisterNotificationHandler + TdiDeregisterNotificationHandler + TdiRegisterDeviceObject + TdiDeregisterDeviceObject + TdiRegisterAddressChangeHandler + TdiDeregisterAddressChangeHandler + TdiRegisterNetAddress + TdiDeregisterNetAddress + TdiInitialize diff --git a/private/ntos/tdi/wrapper/tdi.rc b/private/ntos/tdi/wrapper/tdi.rc new file mode 100644 index 000000000..6882bb371 --- /dev/null +++ b/private/ntos/tdi/wrapper/tdi.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +#define VER_FILEDESCRIPTION_STR "TDI Wrapper" +#define VER_INTERNALNAME_STR "tdi.sys" +#define VER_ORIGINALFILENAME_STR "tdi.sys" + +#include "common.ver" + diff --git a/private/ntos/tdi/wrapper/tdidebug.h b/private/ntos/tdi/wrapper/tdidebug.h new file mode 100644 index 000000000..e4aba7eed --- /dev/null +++ b/private/ntos/tdi/wrapper/tdidebug.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + tdidebug.h + +Abstract: + + This module contains code which assists the process of debugging an NT + TDI client. + +Author: + + David Beaver (dbeaver) 28 June 1991 + +Environment: + + Kernel mode + +Revision History: + + All code moved in from other XNS and NBF locations at creation + + +--*/ + +#if DBG +#include <stdarg.h> +#include <stdio.h> + +VOID +TdiPrintf( + char *Format, + ... + ); + +VOID +TdiFormattedDump( + PCHAR far_p, + ULONG len + ); + +VOID +TdiHexDumpLine( + PCHAR pch, + ULONG len, + PCHAR s, + PCHAR t + ); +#endif diff --git a/private/ntos/tdi/wrapper/tdipnp.c b/private/ntos/tdi/wrapper/tdipnp.c new file mode 100644 index 000000000..615e19715 --- /dev/null +++ b/private/ntos/tdi/wrapper/tdipnp.c @@ -0,0 +1,1029 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tdipnp.c + +Abstract: + + TDI routines for supporting PnP in transports and transport clients. + +Author: + + Henry Sanders (henrysa) Oct. 10, 1995 + +Revision History: + + Who When What + -------- -------- ---------------------------------------------- + henrysa 10-10-95 created + +Notes: + +--*/ + +#include <ntddk.h> +#include <ndis.h> +#include <tdi.h> +#include <tdikrnl.h> +#include "tdipnp.h" + +KSPIN_LOCK TDIListLock; + +LIST_ENTRY BindClientList; + +LIST_ENTRY NetAddressClientList; + +LIST_ENTRY BindProviderList; + +LIST_ENTRY NetAddressProviderList; + +LIST_ENTRY BindRequestList; + +LIST_ENTRY NetAddressRequestList; + +BOOLEAN BindRequestInProgress; + +PETHREAD BindRequestThread; + +BOOLEAN AddressRequestInProgress; + +PETHREAD AddressRequestThread; + +VOID +TdiNotifyClientList ( + PLIST_ENTRY ListHead, + PVOID Info, + BOOLEAN Added +) + +/*++ + +Routine Description: + + Called when a new provider is added or deleted. We walk the specified + client list and notify all of the clients of what just occured. + +Arguments: + + ListHead - Head of list to walk. + Info - Information describing the provider that changed. + Added - True if a provider was added, false otherwise + +Return Value: + + + +--*/ + +{ + PLIST_ENTRY Current; + PTDI_PROVIDER_COMMON ProviderCommon; + PTDI_NOTIFY_ELEMENT NotifyElement; + PTDI_PROVIDER_RESOURCE Provider; + + Current = ListHead->Flink; + + + // The Info parameter is actually a pointer to a PROVIDER_COMMON + // structure, so get back to that so that we can find out what kind of + // provider this is. + + ProviderCommon = (PTDI_PROVIDER_COMMON)Info; + + Provider = CONTAINING_RECORD( + ProviderCommon, + TDI_PROVIDER_RESOURCE, + Common + ); + + // Walk the input client list, and for every element in it + // notifhy the client. + + while (Current != ListHead) { + + NotifyElement = CONTAINING_RECORD( + Current, + TDI_NOTIFY_ELEMENT, + Common.Linkage + ); + + if (Provider->Common.Type == TDI_RESOURCE_DEVICE) { + // This is a device object provider. + + // This must be a notify bind element. + + + // If this is a device coming in, call the bind handler, + // else call the unbind handler. + + if (Added) { + (*(NotifyElement->Specific.BindElement.BindHandler))( + &Provider->Specific.Device.DeviceName + ); + } else { + (*(NotifyElement->Specific.BindElement.UnbindHandler))( + &Provider->Specific.Device.DeviceName + ); + } + } else { + + // This is a notify net address element. If this is + // an address coming in, call the add address handler, + // otherwise call delete address handler. + + if (Added) { + (*(NotifyElement->Specific.AddressElement.AddHandler))( + &Provider->Specific.NetAddress.Address + ); + } else { + (*(NotifyElement->Specific.AddressElement.DeleteHandler))( + &Provider->Specific.NetAddress.Address + ); + } + } + + // Get the next one. + + Current = Current->Flink; + + } +} + +VOID +TdiNotifyNewClient ( + PLIST_ENTRY ListHead, + PVOID Info +) + +/*++ + +Routine Description: + + Called when a new client is added and we want to notify it of existing + providers. The client can be for either binds or net addresses. We + walk the specified input list, and notify the client about each entry in + it. + +Arguments: + + ListHead - Head of list to walk. + Info - Information describing the new client to be notified. + +Return Value: + + + +--*/ + +{ + PLIST_ENTRY CurrentEntry; + PTDI_NOTIFY_COMMON NotifyCommon; + PTDI_PROVIDER_RESOURCE Provider; + PTDI_NOTIFY_ELEMENT NotifyElement; + + CurrentEntry = ListHead->Flink; + + // The info is actually a pointer to a client notify element. Cast + // it to the common type. + + NotifyCommon = (PTDI_NOTIFY_COMMON)Info; + + // Walk the input provider list, and for every element in it notify + // the new client. + + while (CurrentEntry != ListHead) { + + // If the new client is for bind notifys, set up to call it's bind + // handler. + + // Put the current provider element into the proper form. + + Provider = CONTAINING_RECORD( + CurrentEntry, + TDI_PROVIDER_RESOURCE, + Common.Linkage + ); + + NotifyElement = CONTAINING_RECORD( + NotifyCommon, + TDI_NOTIFY_ELEMENT, + Common + ); + + if (NotifyCommon->Type == TDI_NOTIFY_DEVICE) { + + // This is a bind notify client. + + + + (*(NotifyElement->Specific.BindElement.BindHandler))( + &Provider->Specific.Device.DeviceName + ); + + } else { + // This is an address notify client. + + (*(NotifyElement->Specific.AddressElement.AddHandler))( + &Provider->Specific.NetAddress.Address + ); + } + + // And do the next one. + + CurrentEntry = CurrentEntry->Flink; + + } +} + +NTSTATUS +TdiHandleSerializedRequest ( + PVOID RequestInfo, + UINT RequestType +) + +/*++ + +Routine Description: + + Called when we want to process a request relating to one of the + lists we manage. We look to see if we are currently processing such + a request - if we are, we queue this for later. Otherwise we'll + remember that we are doing this, and we'll process this request. + When we're done we'll look to see if any more came in while we were + busy. + +Arguments: + + RequestInfo - Reqeust specific information. + RequestType - The type of the request. + +Return Value: + + Request completion status. + + +--*/ + +{ + KIRQL OldIrql; + PLIST_ENTRY List; + PLIST_ENTRY ClientList; + PLIST_ENTRY ProviderList; + PLIST_ENTRY RequestList; + PBOOLEAN SerializeFlag; + PETHREAD *RequestThread; + PTDI_SERIALIZED_REQUEST Request; + PKEVENT BlockedEvent = NULL; + PTDI_NOTIFY_COMMON NotifyElement; + PTDI_PROVIDER_RESOURCE ProviderElement; + + ExAcquireSpinLock( + &TDIListLock, + &OldIrql + ); + + if (RequestType <= TDI_MAX_BIND_REQUEST) { + ClientList = &BindClientList; + ProviderList = &BindProviderList; + RequestList = &BindRequestList; + SerializeFlag = &BindRequestInProgress; + RequestThread = &BindRequestThread; + } else { + ClientList = &NetAddressClientList; + ProviderList = &NetAddressProviderList; + RequestList = &NetAddressRequestList; + SerializeFlag = &AddressRequestInProgress; + RequestThread = &AddressRequestThread; + } + + // If we're not already here, handle it right away. + + if (!(*SerializeFlag)) { + + *SerializeFlag = TRUE; + + // Save the identity of the thread we're doing this in in case someone + // tries to delete a client, which needs to block. In that case we'll + // check to make sure it's not being done in the same thread we're using + // to prevent deadlock. + + *RequestThread = PsGetCurrentThread(); + + for (;;) { + + // We're done with the lock for now, so free it. + + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + + // Figure out the type of request we have here. + + switch (RequestType) { + case TDI_REGISTER_BIND_NOTIFY: + case TDI_REGISTER_ADDRESS_NOTIFY: + // This is a client register bind or address handler request. + + // Insert this one into the registered client list. + NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo; + InsertTailList( + ClientList, + &NotifyElement->Linkage, + ); + + // Call TdiNotifyNewClient to notify this new client of all + // all existing providers. + + TdiNotifyNewClient( + ProviderList, + RequestInfo + ); + + break; + + case TDI_DEREGISTER_BIND_NOTIFY: + case TDI_DEREGISTER_ADDRESS_NOTIFY: + + // This is a client deregister request. Pull him from the + // client list, free it, and we're done. + + NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo; + RemoveEntryList(&NotifyElement->Linkage); + + ExFreePool(NotifyElement); + + break; + + case TDI_REGISTER_DEVICE: + case TDI_REGISTER_ADDRESS: + + // A provider is registering a device or address. Add him to + // the appropriate provider list, and then notify all + // existing clients of the new device. + + ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo; + + InsertTailList( + ProviderList, + &ProviderElement->Common.Linkage + ); + + // Call TdiNotifyClientList to do the hard work. + + TdiNotifyClientList( + ClientList, + RequestInfo, + TRUE + ); + break; + + case TDI_DEREGISTER_DEVICE: + case TDI_DEREGISTER_ADDRESS: + + // A provider device or address is deregistering. Pull the + // resource from the provider list, and notify clients that + // he's gone. + + ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo; + RemoveEntryList(&ProviderElement->Common.Linkage); + + TdiNotifyClientList( + ClientList, + RequestInfo, + FALSE + ); + + // Free the tracking structure we had. + + if (RequestType == TDI_DEREGISTER_DEVICE) { + ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer); + } + ExFreePool(ProviderElement); + + break; + default: + break; + } + + // If there was an event specified with this request, signal + // it now. This should only be a client deregister request, which + // needs to block until it's completed. + + if (BlockedEvent != NULL) { + KeSetEvent(BlockedEvent, 0, FALSE); + } + + // Get the lock, and see if more requests have come in while + // we've been busy. If they have, we'll service them now, otherwise + // we'll clear the in progress flag and exit. + + ExAcquireSpinLock( + &TDIListLock, + &OldIrql + ); + + if (!IsListEmpty(RequestList)) { + + // The request list isn't empty. Pull the next one from + // the list and process it. + + List = RemoveHeadList(RequestList); + + Request = CONTAINING_RECORD(List, TDI_SERIALIZED_REQUEST, Linkage); + + RequestInfo = Request->Element; + RequestType = Request->Type; + BlockedEvent = Request->Event; + + ExFreePool(Request); + + } else { + + // The request list is empty. Clear the flag and we're done. + + *SerializeFlag = FALSE; + + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + break; + } + } + + return STATUS_SUCCESS; + } else { + + // We're already running, so we'll have to queue. If this is a + // deregister bind or address notify call, we'll see if the issueing + // thread is the same one that is currently busy. If so, we'll fail + // to avoid deadlock. Otherwise for deregister calls we'll block until + // it's done. + + Request = (PTDI_SERIALIZED_REQUEST)ExAllocatePool( + NonPagedPool, + sizeof(TDI_SERIALIZED_REQUEST) + ); + + if (Request == NULL) { + + // Couldn't get a request. + + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Got the request. + Request->Element = RequestInfo; + Request->Type = RequestType; + Request->Event = NULL; + + if ( + RequestType == TDI_DEREGISTER_BIND_NOTIFY || + RequestType == TDI_REGISTER_BIND_NOTIFY || + RequestType == TDI_DEREGISTER_ADDRESS_NOTIFY + ) { + + // This is a deregister request. See if it's the same thread + // that's busy. If not, block for it to complete. + + if (*RequestThread == PsGetCurrentThread()) { + + // It's the same one, so give up now. + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + + ExFreePool(Request); + + return STATUS_NETWORK_BUSY; + } else { + // He's not currently busy, go ahead and block. + + KEVENT Event; + NTSTATUS Status; + + KeInitializeEvent( + &Event, + SynchronizationEvent, + FALSE + ); + + Request->Event = &Event; + + // Put this guy on the end of the request list. + + InsertTailList(RequestList, &Request->Linkage); + + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + + Status = KeWaitForSingleObject( + &Event, + UserRequest, + KernelMode, + FALSE, + NULL + ); + + // I don't know what we'd do is the wait failed.... + + return STATUS_SUCCESS; + } + } else { + + // This isn't a deregister request, so there's no special handling + // necessary. Just put the request on the end of the list. + + InsertTailList(RequestList, &Request->Linkage); + + ExReleaseSpinLock( + &TDIListLock, + OldIrql + ); + + return STATUS_SUCCESS; + } + } + +} + +NTSTATUS +TdiRegisterNotificationHandler( + IN TDI_BIND_HANDLER BindHandler, + IN TDI_UNBIND_HANDLER UnbindHandler, + OUT HANDLE *BindingHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI client wants to register for + notification of the arrival of TDI providers. We allocate a + TDI_NOTIFY_ELEMENT for the provider and then call the serialized + worker routine to do the real work. + +Arguments: + + BindHandler - A pointer to the routine to be called when + a new provider arrives. + UnbindHandler - A pointer to the routine to be called when a + provider leaves. + BindingHandle - A handle we pass back that identifies this + client to us. + +Return Value: + + The status of the attempt to register the client. + +--*/ + + +{ + PTDI_NOTIFY_ELEMENT NewElement; + NTSTATUS Status; + + // + // Make sure Tdi is intialized. If there are no pnp transports, then this is + // called by the tdi client and if tdi is not initialized, it is toast + // Multiple calls to TdiIntialize are safe since only the first one does + // the real work + // + TdiInitialize(); + + + // First, try and allocate the needed resource. + + NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool( + NonPagedPool, + sizeof(TDI_NOTIFY_ELEMENT) + ); + + // If we couldn't get it, fail the request. + if (NewElement == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Fill in the basic stuff. + NewElement->Common.Type = TDI_NOTIFY_DEVICE; + NewElement->Specific.BindElement.BindHandler = BindHandler; + NewElement->Specific.BindElement.UnbindHandler = UnbindHandler; + + *BindingHandle = (HANDLE)NewElement; + + + // Now call HandleBindRequest to handle this one. + + Status = TdiHandleSerializedRequest( + NewElement, + TDI_REGISTER_BIND_NOTIFY + ); + + if (Status != STATUS_SUCCESS) { + ExFreePool(NewElement); + } + + return Status; + + +} + +NTSTATUS +TdiDeregisterNotificationHandler( + IN HANDLE BindingHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI client wants to deregister a + previously registered bind notification handler. All we really + do is call TdiHandleSerializedRequest, which does the hard work. + +Arguments: + + BindingHandle - A handle we passed back to the client + on the register call. This is really + a pointer to the notify element. + +Return Value: + + The status of the attempt to deregister the client. + +--*/ + +{ + NTSTATUS Status; + + Status = TdiHandleSerializedRequest( + BindingHandle, + TDI_DEREGISTER_BIND_NOTIFY + ); + + return Status; + +} + +NTSTATUS +TdiRegisterDeviceObject( + IN PUNICODE_STRING DeviceName, + OUT HANDLE *RegistrationHandle +) + +/*++ + +Routine Description: + + Called when a TDI provider wants to register a device object. + +Arguments: + + DeviceName - Name of the device to be registered. + + RegistrationHandle - A handle we pass back to the provider, + identifying this registration. + +Return Value: + + The status of the attempt to register the provider. + +--*/ + + +{ + PTDI_PROVIDER_RESOURCE NewResource; + NTSTATUS Status; + PWCHAR Buffer; + + TdiInitialize(); + + // First, try and allocate the needed resource. + + NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool( + NonPagedPool, + sizeof(TDI_PROVIDER_RESOURCE) + ); + + // If we couldn't get it, fail the request. + if (NewResource == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + + // Try and get a buffer to hold the name. + + Buffer = (PWCHAR)ExAllocatePool( + NonPagedPool, + DeviceName->MaximumLength + ); + + if (Buffer == NULL) { + ExFreePool(NewResource); + return STATUS_INSUFFICIENT_RESOURCES; + } + // Fill in the basic stuff. + NewResource->Common.Type = TDI_RESOURCE_DEVICE; + NewResource->Specific.Device.DeviceName.MaximumLength = + DeviceName->MaximumLength; + + NewResource->Specific.Device.DeviceName.Buffer = Buffer; + + RtlCopyUnicodeString( + &NewResource->Specific.Device.DeviceName, + DeviceName + ); + + *RegistrationHandle = (HANDLE)NewResource; + + + // Now call HandleBindRequest to handle this one. + + Status = TdiHandleSerializedRequest( + NewResource, + TDI_REGISTER_DEVICE + ); + + if (Status != STATUS_SUCCESS) { + ExFreePool(Buffer); + ExFreePool(NewResource); + } + + return Status; + + +} + +NTSTATUS +TdiDeregisterDeviceObject( + IN HANDLE RegistrationHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI provider want's to deregister + a device object. + +Arguments: + + RegistrationHandle - A handle we passed back to the provider + on the register call. This is really + a pointer to the resource element. + +Return Value: + + The status of the attempt to deregister the provider. + +--*/ + +{ + NTSTATUS Status; + + Status = TdiHandleSerializedRequest( + RegistrationHandle, + TDI_DEREGISTER_DEVICE + ); + + return Status; + +} + +NTSTATUS +TdiRegisterAddressChangeHandler( + IN TDI_ADD_ADDRESS_HANDLER AddHandler, + IN TDI_DEL_ADDRESS_HANDLER DeleteHandler, + OUT HANDLE *BindingHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI client wants to register for + notification of the arrival of network addresses. We allocate a + TDI_NOTIFY_ELEMENT for the provider and then call the serialized + worker routine to do the real work. + +Arguments: + + AddHandler - A pointer to the routine to be called when + a new address arrives. + DeleteHandler - A pointer to the routine to be called when an + address leaves. + BindingHandle - A handle we pass back that identifies this + client to us. + +Return Value: + + The status of the attempt to register the client. + +--*/ + + +{ + PTDI_NOTIFY_ELEMENT NewElement; + NTSTATUS Status; + + + // First, try and allocate the needed resource. + + NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool( + NonPagedPool, + sizeof(TDI_NOTIFY_ELEMENT) + ); + + // If we couldn't get it, fail the request. + if (NewElement == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Fill in the basic stuff. + NewElement->Common.Type = TDI_NOTIFY_NET_ADDRESS; + NewElement->Specific.AddressElement.AddHandler = AddHandler; + NewElement->Specific.AddressElement.DeleteHandler = DeleteHandler; + + *BindingHandle = (HANDLE)NewElement; + + + // Now call HandleBindRequest to handle this one. + + Status = TdiHandleSerializedRequest( + NewElement, + TDI_REGISTER_ADDRESS_NOTIFY + ); + + if (Status != STATUS_SUCCESS) { + ExFreePool(NewElement); + } + + return Status; + + +} + +NTSTATUS +TdiDeregisterAddressChangeHandler( + IN HANDLE BindingHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI client wants to deregister a + previously registered address change notification handler. All we + really do is call TdiHandleSerializedRequest, which does the hard work. + +Arguments: + + BindingHandle - A handle we passed back to the client + on the register call. This is really + a pointer to the notify element. + +Return Value: + + The status of the attempt to deregister the client. + +--*/ + +{ + NTSTATUS Status; + + Status = TdiHandleSerializedRequest( + BindingHandle, + TDI_DEREGISTER_ADDRESS_NOTIFY + ); + + return Status; + +} + +NTSTATUS +TdiRegisterNetAddress( + IN PTA_ADDRESS Address, + OUT HANDLE *RegistrationHandle +) + +/*++ + +Routine Description: + + Called when a TDI provider wants to register a new net address. + +Arguments: + + Address - New net address to be registered. + + RegistrationHandle - A handle we pass back to the provider, + identifying this registration. + +Return Value: + + The status of the attempt to register the provider. + +--*/ + + +{ + PTDI_PROVIDER_RESOURCE NewResource; + NTSTATUS Status; + + // First, try and allocate the needed resource. + + NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool( + NonPagedPool, + FIELD_OFFSET( + TDI_PROVIDER_RESOURCE, + Specific.NetAddress + ) + + FIELD_OFFSET(TA_ADDRESS, Address) + + Address->AddressLength + ); + + // If we couldn't get it, fail the request. + if (NewResource == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Fill in the basic stuff. + NewResource->Common.Type = TDI_RESOURCE_DEVICE; + NewResource->Specific.NetAddress.Address.AddressLength = + Address->AddressLength; + + NewResource->Specific.NetAddress.Address.AddressType = + Address->AddressType; + + RtlCopyMemory( + NewResource->Specific.NetAddress.Address.Address, + Address->Address, + Address->AddressLength + ); + + *RegistrationHandle = (HANDLE)NewResource; + + + // Now call HandleBindRequest to handle this one. + + Status = TdiHandleSerializedRequest( + NewResource, + TDI_REGISTER_ADDRESS + ); + + if (Status != STATUS_SUCCESS) { + ExFreePool(NewResource); + } + + return Status; + + +} + +NTSTATUS +TdiDeregisterNetAddress( + IN HANDLE RegistrationHandle +) + +/*++ + +Routine Description: + + This function is called when a TDI provider wants to deregister + a net addres. + +Arguments: + + RegistrationHandle - A handle we passed back to the provider + on the register call. This is really + a pointer to the resource element. + +Return Value: + + The status of the attempt to deregister the provider. + +--*/ + +{ + NTSTATUS Status; + + Status = TdiHandleSerializedRequest( + RegistrationHandle, + TDI_DEREGISTER_ADDRESS + ); + + return Status; + +} + diff --git a/private/ntos/tdi/wrapper/tdipnp.h b/private/ntos/tdi/wrapper/tdipnp.h new file mode 100644 index 000000000..ae98e7d02 --- /dev/null +++ b/private/ntos/tdi/wrapper/tdipnp.h @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + tdipnp.h + +Abstract: + + This module contains the definitions for the PnP related code + in the TDI driver. + +Author: + + Henry Sanders (henrysa) 11 Oct 1995 + +Environment: + + Kernel mode + +Revision History: + + + +--*/ + +#ifndef _TDIPNP_ +#define _TDIPNP_ + +// Define the types possible for a TDI_NOTIFY_ELEMENT structure. + +#define TDI_NOTIFY_DEVICE 0 +#define TDI_NOTIFY_NET_ADDRESS 1 + + +// And the types possible for a TDI_PROVIDER_RESOURCE structure. + +#define TDI_RESOURCE_DEVICE 0 +#define TDI_RESOURCE_NET_ADDRESS 1 + +// +// Define the types of bind requests possible. + +#define TDI_REGISTER_BIND_NOTIFY 0 +#define TDI_DEREGISTER_BIND_NOTIFY 1 +#define TDI_REGISTER_DEVICE 2 +#define TDI_DEREGISTER_DEVICE 3 +#define TDI_REGISTER_ADDRESS_NOTIFY 4 +#define TDI_DEREGISTER_ADDRESS_NOTIFY 5 +#define TDI_REGISTER_ADDRESS 6 +#define TDI_DEREGISTER_ADDRESS 7 + +#define TDI_MAX_BIND_REQUEST TDI_DEREGISTER_DEVICE + +// +// This is the definition of the common part of a TDI_NOTIFY_ELEMENT structure. +// + +typedef struct _TDI_NOTIFY_COMMON { + LIST_ENTRY Linkage; + UCHAR Type; +} TDI_NOTIFY_COMMON, *PTDI_NOTIFY_COMMON; + +// +// The definition of the TDI_NOTIFY_BIND structure. +// + +typedef struct _TDI_NOTIFY_BIND { + TDI_BIND_HANDLER BindHandler; + TDI_UNBIND_HANDLER UnbindHandler; +} TDI_NOTIFY_BIND, *PTDI_NOTIFY_BIND; + +// +// The definition of a TDI_NOTIFY_ADDRESS structure, +// +typedef struct _TDI_NOTIFY_ADDRESS { + TDI_ADD_ADDRESS_HANDLER AddHandler; + TDI_DEL_ADDRESS_HANDLER DeleteHandler; +} TDI_NOTIFY_ADDRESS, *PTDI_NOTIFY_ADDRESS; + + +// +// This is the definition of a TDI_NOTIFY_ELEMENT stucture. +// + +typedef struct _TDI_NOTIFY_ELEMENT { + TDI_NOTIFY_COMMON Common; + union { + TDI_NOTIFY_BIND BindElement; + TDI_NOTIFY_ADDRESS AddressElement; + } Specific; +} TDI_NOTIFY_ELEMENT, *PTDI_NOTIFY_ELEMENT; + + +// +// This is the definition of the common part of a TDI_PROVIDER_RESOURCE structure. +// + +typedef struct _TDI_PROVIDER_COMMON { + LIST_ENTRY Linkage; + UCHAR Type; +} TDI_PROVIDER_COMMON, *PTDI_PROVIDER_COMMON; + +// +// The definition of the TDI_PROVIDER_DEVICE structure. +// + +typedef struct _TDI_PROVIDER_DEVICE { + UNICODE_STRING DeviceName; +} TDI_PROVIDER_DEVICE, *PTDI_PROVIDER_DEVICE; + +// +// The definition of the TDI_PROVIDER_NET_ADDRESS structure. +// + +typedef struct _TDI_PROVIDER_NET_ADDRESS { + TA_ADDRESS Address; +} TDI_PROVIDER_NET_ADDRESS, *PTDI_PROVIDER_NET_ADDRESS; + +// +// This is the definition of a TDI_PROVIDER_RESOURCE stucture. +// + +typedef struct _TDI_PROVIDER_RESOURCE { + TDI_PROVIDER_COMMON Common; + union { + TDI_PROVIDER_DEVICE Device; + TDI_PROVIDER_NET_ADDRESS NetAddress; + } Specific; +} TDI_PROVIDER_RESOURCE, *PTDI_PROVIDER_RESOURCE; + +// +// Structure of a bind list request. +// + +typedef struct _TDI_SERIALIZED_REQUEST { + LIST_ENTRY Linkage; + PVOID Element; + UINT Type; + PKEVENT Event; + +} TDI_SERIALIZED_REQUEST, *PTDI_SERIALIZED_REQUEST; + + +// External defintions for global variables. + +extern KSPIN_LOCK TDIListLock; + +extern LIST_ENTRY BindClientList; + +extern LIST_ENTRY NetAddressClientList; + +extern LIST_ENTRY BindProviderList; + +extern LIST_ENTRY NetAddressProviderList; + +extern LIST_ENTRY BindRequestList; + +extern LIST_ENTRY NetAddressRequestList; + + +#endif // _TDIPNP |