summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/wrapper
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/wrapper
downloadNT4.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.c723
-rw-r--r--private/ntos/tdi/wrapper/makefile6
-rw-r--r--private/ntos/tdi/wrapper/sources49
-rw-r--r--private/ntos/tdi/wrapper/tdi.c1737
-rw-r--r--private/ntos/tdi/wrapper/tdi.def44
-rw-r--r--private/ntos/tdi/wrapper/tdi.pnp44
-rw-r--r--private/ntos/tdi/wrapper/tdi.rc12
-rw-r--r--private/ntos/tdi/wrapper/tdidebug.h52
-rw-r--r--private/ntos/tdi/wrapper/tdipnp.c1029
-rw-r--r--private/ntos/tdi/wrapper/tdipnp.h163
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